I/O输入输出流

1. 编码问题

从一种形式或格式转换为另一种形式的过程也称为计算机编程语言的代码简称编码。而这个转换的方式就是编码方式。
将字符串“例子ABC”分别以gbkutf-8utf-16be编码方式转化成字节,如下:

public class Coding {
    public static void printByEncoding(String s, String encoding){
        try {
            byte[] bytes = s.getBytes(encoding);
            System.out.print("encoding " + encoding + " : ");
            for (byte b : bytes) {
                //把字节(转换成了int)以16进制的方式显示
                System.out.print(Integer.toHexString(b & 0xff) + " ");
            }
            System.out.println();
        }catch (UnsupportedEncodingException e){
            System.out.println("unsupportded encoding: " + encoding);
        }
    }
    public static void main(String[] args) {
        String s = "例子ABC";
        //gbk编码:中文两个字节,英文一个字节
        Coding.printByEncoding(s, "gbk");
        //utf-8编码:中文三个字节,英文一个字节
        Coding.printByEncoding(s, "utf-8");
        // utf-16be编码,中文两个字节,英文两个字节
        Coding.printByEncoding(s, "utf-16be");
    }

输出结果为:

encoding gbk : c0 fd d7 d3 41 42 43 
encoding utf-8 : e4 be 8b e5 ad 90 41 42 43 
encoding utf-16be : 4f 8b 5b 50 0 41 0 42 0 43 

当你的字节序列是某种编码时,这时候想把字节序列变成字符串,也需要这种编码方式,否则会出现乱码

 try {
            String str1 = new String(s.getBytes("utf-16be"));
            System.out.println(str1);

            String str2 = new String(s.getBytes("utf-16be"), "utf-16be");
            System.out.println(str2);
        }catch (UnsupportedEncodingException e){
            System.out.println("unsupportded encoding: " );
        }

输出结果为:

O�[P A B C
例子ABC

文本文件就是字节序列,它可以是任何编码的字节序列。

2. File类

java.io.File类用于表示文件(目录)。File类只用于表示文件(目录)的信息(名称、大小),不能用于文件内容的访问。

File file1 = new File("文件/目录路径"); 
File file2 = new File(File parent, String child);
File file3 = new File(String parent, String child) 
方法 描述
boolean exists() 判断文件/目录 是否存在
boolean mkdir() 创建目录
void createNewFile() 创建目录
delete() 删除文件/目录
boolean isDirectory() 是否是一个目录,如果不是目录or目录不存在返回false
boolean isFile() 是否是一个文件
String getName() 返回文件/目录名。
String getAbsolutePath() 返回抽象路径名的绝对路径名字符串。
String getParent() / File getParentFile() 获取父路径
long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
String[] list() 返回由包含在目录中的文件和目录的名称所组成的字符串数组
File[] listFiles() 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。
...... ......

eg:遍历目录

package com.company;

import java.io.File;
import java.util.Stack;

/**
 * FileItem表示 文件和文件在第几层
 */
public class FileItem {
    public File file;
    public int depth ;

    public FileItem(File file, int depth) {
        this.file = file;
        this.depth = depth;
    }
    //遍历文件or目录
    public static void printFiles(String path){
        //用于存放待访问的节点
        Stack<FileItem> stack = new Stack<FileItem>();
        //根节点入栈
        stack.push( new FileItem(new File("F:\\study"), 0) );
        while(!stack.empty() ) {
            FileItem item = stack.pop();
            File file = item.file;
            int depth = item.depth;
            //打出文件名,按层数缩进
            System.out.println(new String(" ".repeat(2*depth) + file.getName()) );
            if(file.exists() && file.isDirectory()){
                //遍历下一层
                File[] fileList = file.listFiles();
                for(File it: fileList){
                    //下一层入栈
                    stack.push( new FileItem(it, depth+1) );
                }
            }
        }
    }
    public static void main(String[] args) {
      printFiles("F://");

    }

}
 

3. RandomAccessFile

RandomAccessFile是Java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,即可以访问文件的任意位置。

  • (1) java文件模型
    在硬盘上的文件是bye bye bye存储的,是数据的集合。
  • (2) 打开文件
    打开文件时,可以选择两种模式:“rw"(读写),"r"(只读)。
RandomAccessFile raf = new RandomAccessFile(file, "rw");

由于RandomAccessFile支持随机访问文件,需要一个文件指针来指定位置。打开文件时指针在开题pointer = 0;

  • (3) 写方法
raf.write(int) //只写一个字节,同时指针指向下一个位置。
  • (4) 读方法
int b = raf.read(); //读一个字节
  • (5) 文件读写完成后一定要关闭。

4. 字节流

4.1 InputStream和OutputStream

InputStream 和 OutputStream为各种输入输出字节流的基类,所有字节流都继承这两个基类。而且InputStream 和 OutputStream为抽象类,不进行具体的实现。
InputStream抽象了应用程序读取数据的方式。
OutputStream抽象了应用程序写出数据的方式。

  • 输入流常用方法
方法名 描述
int read() throws IOException 读取一个字节无符号填充到int低八位,-1是EOF
int read( byte[] buf ) throws IOException 读取数据填充到字节数组buf
int read(byte[] buf, int start, int size) throws IOException /读取数据填充到字节数组buf
void close() throws IOException 关闭输入流
  • 输出流基本方法
方法名 描述
void write(int b) throws IOException 写出一个byte到流,b的低八位
void write( byte[] buf ) throws IOException 将buf字节数组都写入到流
void write(byte[] buf, int start, int size) throws IOException 将buf字节数组都写入到流
void close() throws IOException 关闭输出流

4.2 FileInputStream和FileOutputStream

FileInputStream具体实现了在文件上读取数据。
FileOutputStream具体实现了将byte数据写入文件.

  • 读取文件
 /**
     * 通过int读取指定文件内容,按照16进制输出到控制台
     */
      public  static void printHexByInt(String filename) throws IOException{
        //把文件作为字节流进行读操作
        FileInputStream in = new FileInputStream(filename); 
        int b;
        while ( (b=in.read()) != -1 ){
            System.out.print(Integer.toHexString(b) + " ");
        }
        in.close();

    }
    /**
     * 通过byte读取指定文件内容,按照16进制输出到控制台
     */
    public  static void printHexByBytes(String filename) throws IOException{
        //把文件作为字节流进行读操作
        FileInputStream in = new FileInputStream(filename);
        byte[] buf = new byte[1024]; //随便大小都可,大一点可能更快
        //从in中批量读取字节, 最多读取 buf.length个,返回读到的数据的个数
        //int bytes = in.read(buf);
        int bytes = 0;
        while ( (  bytes = in.read(buf) ) != -1){

            for(int i = 0; i < bytes; i++){
                System.out.print( Integer.toHexString(buf[i] &0x00ff)+ " ");
            }
        }

    }
  • 写入文件
 //如果该文件不存在,则直接创建;如果存在,删除后创建
        FileOutputStream out = new FileOutputStream("out.dat");
        //如果该文件不存在,则直接创建;如果存在,在后面继续写
        FileOutputStream out2 = new FileOutputStream("out2.dat",true);

        out.write('A'); //写出了‘A’的低八位

        //write只能写八位,那么写一个int需要4次每次8位
        int a = 10;
        out.write(a >>> 24);
        out.write(a >>> 16);
        out.write(a >>> 8 );
        out.write(a );

        //写入byte数组
        byte [] gbk = "中国".getBytes("gbk");
        out.write(gbk);
        
        out.close();
  • 拷贝一个文件
 try {
           InputStream in = new FileInputStream("a.txt");
           OutputStream out = new FileOutputStream("b.txt");

           byte[] buf = new byte[1024];
           int bytes;
           while( (bytes = in.read(buf)) != -1){
               out.write(buf);
               out.flush();
           }
           in.close();
           out.close();
       }catch (FileNotFoundException e1){
           e1.printStackTrace();
       }catch (IOException e2){
           e2.printStackTrace();
       }

4.3 DataInputStream和DataOutputStream

对"流"功能的扩展,可以更加方便地读取int、long、字符等类型数据。

  • DataInputStream: readByte()/readInt() / readDouble() / readUTF()...
  • DataOutputStream:writeByte()/writeInt() / writeDouble() / writeUTF()...

4.2 字节缓冲流BufferedInputStream和BufferedOutputStream

为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能。
从应用程序中把输入放入文件,相当于将一缸水倒入到另一缸水中:

  • FileOutputStream --> write()方法相当于一滴一滴地把水转移过去
  • DataOutputStream->writeXxx()方法会方便点,相当于一瓢一瓢地将水转移过去。
  • BufferedOutputStream-->write方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入缸中。
    拷贝文件:
 try {
           BufferedInputStream is  = new BufferedInputStream(new FileInputStream("a.txt"));
           BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("b.txt"));
           int c;
           while( (c=is.read())!= -1){
               os.write(c);
               os.flush(); //刷新缓存区
           }
           is.close();
           os.close();
       }catch (FileNotFoundException e1){
           e1.printStackTrace();
       }catch (IOException e2){
           e2.printStackTrace();
       }  

5. 字符流Reader/Writer

5.1 文本文件

  • java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)。
  • 文件是 byte byte byte...的数据序列。
  • 文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk) 序列号为byte 的存储结构。

字符的处理,一次处理一个字符。但是字符的底层任然是基本的字节序列 。

5.2 InputStreamReader和OutputStreamWriter

InputStreamReader 完成byte流解析为char流,按照编码解析。
OutputStreamWriter 提供char流到byte流,按照编码处理。

 try {
           FileInputStream is = new FileInputStream("a.txt");
           InputStreamReader isr = new InputStreamReader(is,"gbk");//默认为gbk
           //第一种方法
           int c;
           while( (c = isr.read()) != -1){
               System.out.println( (char)c);
           }
           //第二种方法
           char[] buffer = new char[1024];
           int n;
           while( (n = isr.read(buffer)) !=-1 ){
               String s  = new String(buffer, 0, n);
               System.out.println( s );

           }
           is.close(); 
           isr.close();

       }catch (FileNotFoundException e1){
           e1.printStackTrace();
       }catch (IOException e2){
           e2.printStackTrace();
       }

5.3 BufferedReader / BufferedWriter

  • BufferedReader : readLine 一次第一行
  • BufferedWriter/PrintWriter:写一行

6.对象的序列化和反序列化

对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化 。

  • 序列化流(ObjectOutputStream),是过滤流。--- writeObject
  • 反序列化流(ObjectInputStream) --- readObject

对象必须实现序列化接口Serializable,才能序列化,否则将会出现异常。

  • 序列化:
public class Student implements Serializable {
    private String stuno;
    private  String stuname;
    private  int stuage;

    public Student(String stuno, String stuname, int stuage) {
        this.stuno = stuno;
        this.stuname = stuname;
        this.stuage = stuage;
    }
  • 将Object写入文件
        ObjectOutputStream oos =  new ObjectOutputStream(new FileOutputStream(file));
        Student stu = new Student("10000","loserwang",20);
        oos.writeObject(stu);
        oos.flush();
        oos.close();
  • 从文件中读取Object
 String file = "obj.txt";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        Student s = (Student) ois.readObject();
        System.out.println(s);

添加transient 该元素不会被JVM默认序列化

private transient int name;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348