java 使用IO流进行文件读写

概念

IO流用来处理设备之间的数据传输

java对数据的操作是通过流的方式

java用来操作流的类都在IO包中

流按流向分为两种:输入流、输出流

流按操作类型分为两种:字节流、字符流

IO流常用父类

字节流的抽象父类:InputStream、OutputStream

字符流的抽象父类:Reader、Writer

IO流的使用注意

使用前:要导入IO包中的类

使用时:要进行IO异常处理

使用后:要释放资源

流对象尽量晚开早关

FileInputStream进行文件读取

public class Test {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("test.txt");
        
        //从硬盘上读取一个字节
        int x = fis.read();
        
        System.out.println(x);
        
        //关闭流资源
        fis.close();
                
    }
}

文件的结束标记是  -1

public class Test {
    public static void main(String[] args) throws IOException {
        
        FileInputStream fis = new FileInputStream("test.txt");
        
        int b;
        while((b = fis.read()) != -1) {
            System.out.println(b);
        }
        
        //关闭流资源
        fis.close();
                
    }
}

为什么read返回的是int类型而不是byte类型?

应为FileInputStream可以读取任意类型的文件,如果用byte类型,中间可能出现11111111,而这就是byte类型的-1

程序就会停止执行,后面的就读不到了,如果用int,前面高位不会变成1,也就变成了255,可以保证整个数据的读写

FileOutputStream向文件中写入

将打开的文件清空再重新写入

FileOutputStream在创建时,如果没有这个文件,则会自动创建一个

如果有这个文件,则会先将这个文件清空

public class Test {
    public static void main(String[] args) throws IOException {

        //如果没有此文件则会自动创建一个
        FileOutputStream fos = new FileOutputStream("test.txt");
        
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        
        fos.close();
                
    }
}

如果想以追加的方式操作文件,要给第二个参数为true

public class Test {
    public static void main(String[] args) throws IOException {

        FileOutputStream fos = new FileOutputStream("test.txt", true);
        
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        
        fos.close();
                
    }
}

使用FileInputStream和FileOutputStream进行拷贝

逐个字节拷贝

public class Test {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("test.jpg");
        FileOutputStream fos = new FileOutputStream("test_copy.jpg");
        
        int b;
        while((b = fis.read()) != -1) {
            fos.write(b);
        }
        
        fis.close();
        fos.close();
                
    }
}

FileInputStream里的available方法:

返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数

使用字节数组将文件一次性读取和写入

public class Test {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("9.jpg");
        FileOutputStream fos = new FileOutputStream("test_copy.jpg");
        
        //获取文件的字节数
        int len = fis.available();
        //创建和文件一样大小的字节数组
        byte[] arr = new byte[len];
        //将文件一次性读进来
        fis.read(arr);
        //将文件一次性写入
        fos.write(arr);
        
        fis.close();
        fos.close();
                
    }
}

而对于某些大文件,需要创建很大的字节数组,有可能导致内存溢出

所以可以创建合适大小的字节数组,一部分一部分读取

public class Test {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("test.jpg");
        FileOutputStream fos = new FileOutputStream("test_copy.jpg");
        
        //小文件一般定义为16的整数倍,大文件大小一般定义为1024的整数倍
        byte[] arr = new byte[1024]; //存放每次读取的字节
        int len; //记录每次读取的字节个数
        
        while((len = fis.read(arr)) != -1) {
            fos.write(arr, 0, len);
        }
        
        fis.close();
        fos.close();
                
    }
}

使用BufferedInputStream和BufferedOutputStream

这两个是对FileInputStream和FileOutputStream的包装

在进行读取时,会预先将一部分读入内存,然后其实是在内存中读取

读完了在进行下一部分的读取

所以同样是一个字节一个字节读取,但是使用Buffered会更快

因为内存的速度比硬盘快

public class Test {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("9.jpg");
        FileOutputStream fos = new FileOutputStream("test_copy.jpg");
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        
        int b;
        while ((b = bis.read()) != -1) {
            bos.write(b);
        }
        
        //仅需要关闭包装后的对象即可
        bis.close();
        bos.close();
    }
}

定义小数组和使用buffer的比较

小数组会比buffer稍微快一点点

flush和close方法的区别

flush用来刷新缓冲区

close用来关闭流

close方法具备刷新的功能,在关闭流之前会进行刷新,刷新之后不能继续写入

flush方法仅仅是刷新缓冲区的功能,刷新完之后可以继续写入

字节流读写中文的问题

字节流读取中文会出现各种乱码,因为不确定每个字符所占的字节数

public class Test {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("test.txt");
        byte[] arr = new byte[2];
        int len;
        
        while((len = fis.read(arr)) != -1) {
            System.out.println(new String(arr, 0, len));
        }
        
    }
}

写出中文时要将字符串转换成字节数组

public class Test {
    public static void main(String[] args) throws IOException {

        FileOutputStream fos = new FileOutputStream("test.txt");
        
        fos.write("你好啊".getBytes());
        
        fos.close();
        
    }
}

流的标准异常处理代码

1.6

public class Test {
    public static void main(String[] args) throws IOException {

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("9.jpg");
            fos = new FileOutputStream("test_copy.jpg");
            
            int b;
            while((b = fis.read()) != -1) {
                fos.write(b);
            }
        }  finally {
            //关闭时出现异常,则能关一个就关一个
            try {
                if(fis != null)
                    fis.close();
            } finally {
                if(fos != null)
                    fos.close();
            }
        }
    }
}

1.7版本的写法,这种写法可以自动关闭流的功能

public class Test {
    public static void main(String[] args) throws IOException {
    
        try(
                FileInputStream fis = new FileInputStream("test.jpg");
                FileOutputStream fos = new FileOutputStream("test_copy.jpg");
        ) {
            int b;
            while((b = fis.read()) != -1) {
                fos.write(b);
            }
        }

    }
}

字符流

字符流是能够直接读取字符的IO流

对字节流进行了编码表的转换

使用FileReader读取

public class Test {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("test.txt");
        
        int x;
        while((x = fr.read()) != -1) {
            System.out.println((char)x);
        }
        
        fr.close();
    }
}

使用FileWriter进行文件写入

public class Test {
    public static void main(String[] args) throws IOException {
        FileWriter fw = new FileWriter("test.txt");
        
        fw.write("大家好啊");
        
        fw.close();
    }
}

Writer类中有一个2k的小缓冲区,如果不关闭流,写入的内容最后不会刷新进去,可能写入不完全

使用字符流定义小数组进行拷贝

public class Test {
    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("xxx.txt");
        FileWriter fw = new FileWriter("yyy.txt");
        
        char[] arr = new char[1024];
        int len;
        while((len = fr.read()) != -1) {
            fw.write(arr);
        }
        
        fr.close();
        fw.close();
    }
}

使用BufferedReader和BufferedWriter进行字符流读写

public class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("xxx.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("yyy.txt"));
        
        int c;
        while((c = br.read()) != -1) {
            bw.write(c);
        }
        
        br.close();
        bw.close();
    }
}

带缓冲的字符流的readLine和newLine方法

readLine方法每次读取一行

public class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("xxx.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("yyy.txt"));
        
        String line;
        
        while((line = br.readLine()) != null ) {
            bw.write(line);
        }
        
        br.close();
        bw.close();
    }
}

newLine方法写入一个行分隔符,不加的话,所有读取的会被写在一行

public class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("xxx.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("yyy.txt"));
        
        String line;
        
        while((line = br.readLine()) != null ) {
            bw.write(line);
            bw.newLine();
        }
        
        br.close();
        bw.close();
    }
}

newLine与\r\n的区别:

  newLine是跨平台的,\r\n只是windows系统的

LineNumberReader跟踪行号的缓冲区输入流

public class Test {
    public static void main(String[] args) throws IOException {
        LineNumberReader lnr = new LineNumberReader(new FileReader("test.txt"));
        String line;
        
        lnr.setLineNumber(0);  //设置当前行号,默认为零
        while((line = lnr.readLine()) != null) {
            System.out.println(lnr.getLineNumber() + ":" + line);
        }
        
        lnr.close();
    }
}

InputStreamReader和OutputStreamWriter

使用指定编码表进行读写

public class Test {
    public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("test.txt"), "utf-8");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("test_x.txt"), "gbk");
        
        int c;
        while((c = isr.read()) != -1) {
            osw.write(c);
        }
        
        isr.close();
        osw.close();
    }
}

进一步更高效的包装

public class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader br = 
                new BufferedReader(new InputStreamReader(new FileInputStream("utf8.txt"), "utf-8"));
        BufferedWriter bw = 
                new BufferedWriter(new OutputStreamWriter(new FileOutputStream("gbk.txt"), "gbk"));
        
        int c;
        while((c = br.read()) != -1) {
            bw.write(c);
        }
        
        br.close();
        bw.close();
    }
}

猜你喜欢

转载自www.cnblogs.com/wbyixx/p/9460654.html