IO流,小白入门基础知识

IO流

什么是IO流

将文件从C盘复制到D盘,或者网上下载一个文件,这种可以将数据传输的操作,看做一种数据的流动,我们按照流动的方向(C盘到D盘)分为输出output和输入input;

在Java中的IO操作,主要指的是java.io包下的一些常用类使用。通过这些类对数据进行读取(input)和写出(output)。

IO流的分类

按照流的方向分:输入流和输出流;

按照流动的数据类型分:字节流和字符流;

字节流:

  • 输入流:InputStream
  • 输出流:OutputStream

字符流:

  • 输入流:Reader
  • 输出流:Writer

字节流

前序

一切皆字节;计算机所有数据都是以二进制形式存储。

在数据传输时也都是以二进制的形式存储的;后续学习的任何流,在传输时底层都是二进制;

OutputStream

这是一个抽象类,是表示所有字节输出流类的超类;

方法
变量和类型 方法 描述
void close() 关闭此输出流并释放与此流关联的所有系统资源。
void flush() 刷新此输出流并强制写出任何缓冲的输出字节。
static OutputStream nullOutputStream() 返回一个新的 OutputStream ,它丢弃所有字节。
void write(byte[] b) b.length字节从指定的字节数组写入此输出流。
void write(byte[] b, int off, int len) 将从偏移量 off开始的指定字节数组中的 len字节写入此输出流。
abstract void write(int b) 将指定的字节写入此输出流。

close():无论使用字符流还是字节流对数据输入和输出之后,一定要close进行释放;否则在外界无法对该文件操作;

flush():有些流带有缓冲,所有数据都是字节传输,缓冲是先把数据存在内存一个地址中,当存储到一定数量再统一操作。flush就是把缓冲区的数据直接写出去。

nullOutputStream():返回一个新的输出流,用的不多

write(int b):将指定的字节写入此输出流,要写入的字节是是参数b的八个低位;

什么是八个低位:int=4字节=32位,取其最后的8个比特位,前面的24个高位被忽略;所以也就是传入的是int,但是当做字节来用;

8位能表示最大数值=11111111(二进制)=255

FileOutputStream

FileOutputStream是OutputStream的一个很常用的子类,它是一个实体类;每一个FileOutputStream的对象就表示建立某个文件输出的流管道,可以通过这个对象向指定文件输出内容;

public static void main(String[] args) throws IOException {
    
    
        FileOutputStream fos = new FileOutputStream("d://a.txt");
        fos.write(65);
        byte[] bytes1 = {
    
    66,67,68};
        fos.write(bytes1);
        byte[] bytes2 = "EFG".getBytes();
        fos.write(bytes2);
        fos.close();
    	//fos.write(65);
    }

以上输入结果为:ABCDEFG

close()之后流通道关闭不能继续存入数据,否则会报错:Stream Closed。如果后面不再进行数据传输,应该使用close()尽早的关闭。

InputStream

InputStream是字节输入流,作用是将内容读取到程序中来;

方法
abstract int read() 从输入流中读取下一个数据字节。
int read(byte[] b) 从此输入流 b.length最多 b.length字节的数据读 b.length字节数组。

read()是向指定文件中读取一个字节的内容,如果读取完毕则会返回-1;

read(byte[] b),返回值int是数组从文件中读取的字节个数;

在日常的编程中,我们经常使用一组字节的读取方式,这样可以减少IO的创建次数;

FileInputStream

FileInputStreeam是InputStream的子类

构造方法
构造器 描述
FileInputStream(File file) 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj) 使用文件描述符 fdObj创建 FileInputStream ,该文件描述符表示与文件系统中实际文件的现有连接。
FileInputStream(String name) 通过打开与实际文件的连接来创建 FileInputStream ,该文件由文件系统中的路径名 name命名。

从file文件中往程序输入数据;String name中name可以是相对路径,也可以是绝对路径。

举例:

 FileInputStream fis = new FileInputStream("d://a.txt");
        while(true){
    
    
            byte b = (byte)fis.read();//将int转为byte类型
            if(b == -1){
    
    
                break;
            }
            System.out.println((char) b);
        }

read()是一个一个读取文件中的字节,当字节读取完毕后返回-1;

FileInputStream fis = new FileInputStream("d://a.txt");
        byte[] bytes = new byte[10];
        fis.read(bytes);
        System.out.println(new String(bytes));
        fis.read(bytes);
        System.out.println(new String(bytes));
        fis.read(bytes);
        System.out.println(new String(bytes));
        fis.close();

打印结果为:

abcdefghij
klmnopqrst
uvwsyzqrst

原因:创建一个大小为[10]的数组,读取文件时把数组存满,然后第二次读取时从数组第一个元素开始覆盖上一次存储的字节;所以在第三次打印结果为(uvwsyzqrst),因为第三次只有uvwsyz覆盖了前面6个后面四个没有覆盖掉;

如何优化:

byte[] bytes = new byte[10];
int len = fis.read(bytes); //数组从文件中读取的字节个数
System.out.println(new String(bytes,0,len));
len = fis.read(bytes);
System.out.println(new String(bytes,0,len));
len = fis.read(bytes);
System.out.println(new String(bytes,0,len));
fis.close();

new String(bytes,0,len):从数组下标0开始,到len个字节结束;

字符流

文字在UTF-8的存储

文字在UTF-8中,一个文字以1-4个字节大小随机存储。

区别是字符流只能操作文字,字节流能操作任何数据。

Writer

字符输出流和字节输出流很像,只不过是把输出内容通过字节进行封装,字符流里面的数据其实也是字节流,只是单位为字符,一个字符一个字符输出。

FileWriter

FileWriter是Writer的一个子类。

public static void main(String[] args) throws IOException {
    
    
        FileWriter fw = new FileWriter("d://a.txt",true);
     // FileWriter fw = new FileWriter("d://a.txt");
        fw.write("我见青山多妩媚");
        fw.close();

(“d://a.txt”,true):如果要close关闭流后依旧保存原文件里面内容则需要加true;

public static void main(String[] args) throws IOException {
    
    
        FileWriter fw = new FileWriter("d://a.txt");
        fw.append("我见青山多妩媚").append(",").append("料青山见我应如是");
        fw.close();
    }

append的使用

打印结果:我见青山多妩媚,料青山见我应如是

Reader

字符输入流;

int read() 读一个字符。
int read(char[] cbuf) 将字符读入数组。

返回值为int:返回-1则表示已经读取到了文件的尾部;

读一组字符比一个字符效率要高;

FileWriter fw = new FileWriter("d://a.txt");
        fw.append("我见青山多妩媚").append(",").append("料青山见我应如是");
        fw.close();
        FileReader fr = new FileReader("d://a.txt");
        /*while(true){
            int c=fr.read();
            if(c==-1)
                break;
            System.out.print((char)c);
        }*/
        char[] chars = new char[100];
        fr.read(chars);
        System.out.println(new String(chars));
        System.out.println(new String(chars).length());//=100
        fr.close();

以上分别用一个字符和一组字符进行输入。

注意的是: 给的数组长度过长,数组后面没被字符占用的位置同样会被打印出来,打印的是空格;

如何修改:

//fr.read(chars);
//System.out.println(new String(chars));
int len = fr.read(chars);
System.out.println(new String(chars,0,len));

flush刷新管道

字符(假设3个字节)在输出时在读满3字节才会输出,但没读满时会暂时缓存起来。

在输入方到输出方是有个缓存区的。当我们进行字符流时需要加上flush(),不然我们无法把缓冲区的数据写入到文件中去,有时候我们没写是因为调用close()时包含了flush()方法。

字节转换字符流

转换流主要的作用就是将任意的字节流“装饰为”字符流;

输入流转换InputStreamReader

 FileInputStream fis = new FileInputStream("d://a.txt");
        InputStreamReader isr = new InputStreamReader(fis,"utf-8");
        while(true){
    
    
            int c = isr.read();
            if(c==-1){
    
    
                break;
            }
            System.out.print((char) c);
        }

InputStreamReader(fis,“utf-8”):

  1. 参数一:要传入的字节文件
  2. 参数二:指定转换编码名称。参数二可要可不要;

输出流转换OutputStreamWriter

FileOutputStream fos = new FileOutputStream("d://a.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        osw.write("我见青山多妩媚");
        osw.flush();
        osw.close();

Print与BufferedReader

  • Print:
//字符输出
        PrintStream ps = new PrintStream("d://a.txt");
        ps.println("我见青山多妩媚");
        ps.println("料青山见我应如是");

        PrintWriter pw = new PrintWriter("d://a.txt");
        pw.println("我见青山多妩媚");
        pw.println("料青山见我应如是");
        pw.flush();

第一种虽然是字节输出流,但依旧可要输出字符;

第二种是字符输出流,所以需要加flush()才能输出到文本中;

  • BufferedReader

缓存读取流: 将字符输入流转换为 具有缓存一次读取一行的字符读取流,这一个很常用

FileReader fw = new FileReader("d://a.txt");
BufferedReader br = new BufferedReader(fw);
String text1 = br.readLine();
System.out.println(text1);
String text2 = br.readLine();
System.out.println(text2);
String text3 = br.readLine();
System.out.println(text3);

当最后一行没有数据时,打印结果为null;

例:

文本中的数据:

我见青山多妩媚

料青山见我应如是

打印结果:

我见青山多妩媚

料青山见我应如是

null

おすすめ

転載: blog.csdn.net/m0_58702068/article/details/120774474