Java IO流

发布于:2025-07-17 ⋅ 阅读:(18) ⋅ 点赞:(0)

目录

一、IO流的分类

(一)字节流

1、InputStream

InputStream类中的成员方法

FileInputStream的构造方法

read()和read(byte[]b)代码示例:

2、利用Scanner进行字符读取

代码示例:

3、OutputStream

OutputStream中的成员方法

FileOutputStream代码示例

示例一:

示例二:

示例三:

示例四:

示例五:

追加写:

(二)字符流

1、Reader

2、Writer

二、总结


Java中针对文件内容的操作,主要是通过一组“流对象”来实现的。

“流”是一种很形象的比喻,将数据比喻成水流,来定义数据的传输方式。

一、IO流的分类

(一)字节流

字节流读写文件是以字节为单位,是针对二进制文件使用的。

针对读和写,有两个类:InputStream和OutputStream类。

1、InputStream

InputStream用于输入,从文件中读取数据。

但是InputStream 只是一个抽象类,要使用还需要具体的实现类。

InputStream类中的成员方法

read()返回的是字节数据。

read(byte[]b)是将读取到的字节数据读入到数组中,返回的是读取到的字节数。

关于 InputStream 的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream 类,我们现在只关心从文件中读取,所以使用 FileInputStream。

FileInputStream的构造方法

这里的创建对象操作一但成功,就相当于“打开文件”,打开文件进行读写操作之后就要手动释放,否则就会引起“文件资源泄露”。

public class Demo05 {
    public static void main(String[] args) throws IOException {
        File file=new File("./hello.txt");
        file.createNewFile();
        //创建流对象,成功就相当于打开文件
        InputStream inputStream=new FileInputStream(file);
        //没有手动释放
    }
}

为了确保文件必须关闭,采用try+finally的写法:

public class Demo05 {
    public static void main(String[] args) throws IOException {
        File file=new File("./hello.txt");
        file.createNewFile();
        InputStream inputStream=null;
        try{
            inputStream=new FileInputStream(file);
        }finally {
            inputStream.close();
        }
    }
}

优化成try with resources的写法 :

public class Demo05 {
    public static void main(String[] args) throws IOException {
        File file=new File("./hello.txt");
        file.createNewFile();
        try(InputStream inputStream=new FileInputStream(file);){
            
    }
}
read()和read(byte[]b)代码示例:

将文件完全读完的两种方式,第二种的IO次数更少性能更好。

在项目目录下准备好了一个hello.txt 的文件,里面填充 "Hello" 的内容。

public class Demo05 {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream=new FileInputStream("hello.txt");){
            while(true){
                int n=inputStream.read();
                if(n==-1){
                    break;
                }
                //转换类型
                System.out.print((char)n);
            }
        }
    }
}
public class Demo05 {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream=new FileInputStream("hello.txt");){
            byte[]buf=new byte[1024];
            int len;
            while(true){
                len=inputStream.read(buf);
                if(len==-1){
                    break;
                }
                for(int i=0;i<len;i++){
                    //转换类型
                    System.out.print((char)buf[i]);
                }
            }
        }
    }
}

对于第二种写法: 

  • byte[]buf=new byte[1024]作为缓冲区,提高数据读取或者写入的效率。
  • 每次调用 inputStream.read(buf) 时,它会尝试从输入流中读取最多 buf.length 字节的数据到缓冲区 buf 中,并返回实际读取的字节数。
  • 每次 read(buf) 执行时,会将新数据写入 buf 的起始位置,覆盖之前的数据。

2、利用Scanner进行字符读取

上述例子中,我们看到了对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类。

构造方法

说明

Scanner(InputStream is, String charset)

使用charset字符集进行is的扫描读取
代码示例:
public class Demo06 {
    public static void main(String[] args) {
        try(InputStream is=new FileInputStream("hello.txt");){
            try(Scanner sc=new Scanner(is);){
                while(sc.hasNext()){
                    System.out.println(sc.next());
                }
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

Scanner和read()的作用都是从输入流中获取数据。

3、OutputStream

对于OutputStream来说,默认情况下会尝试创建不存在的文件,而InputStream不会。

OutputStream中的成员方法
修饰符及返回值类型 方法签名 说明
void

write(int b)

写入要给字节的数据

void

write(byte[] b)

将b这个字符数组中的数据全部写入os 中

int

write(byte[]b,

int off, int len)

将b这个字符数组中从 off 开始的数据写入os 中,一共写 len 个

void close() 关闭字节流
void

flush()

将可能遗留在缓冲区里的数据flush刷新到设备中

OutputStream同样只是一个抽象类,要使用还需要具体的实现类,我们现在只是关心写入文件中,所以使用FileOutputStream 

FileOutputStream代码示例
示例一:
public class Demo07 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os=new FileOutputStream("output.txt");) {
            os.write('H');
            os.write('e');
            os.write('l');
            os.write('l');
            os.write('o');
            //不要忘记flush
            os.flush();
        }
    }
}
示例二:
public class Demo07 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os=new FileOutputStream("output.txt");) {
            byte[]b=new byte[]{
                    (byte)'H',(byte)'e',(byte)'l',(byte)'l',(byte)'o'
            };
            os.write(b);
            //不要忘记flush
            os.flush();
        }
    }
}
示例三:
public class Demo07 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os=new FileOutputStream("output.txt");) {
            byte[]b=new byte[]{
                    (byte)'H',(byte)'e',(byte)'l',(byte)'l',(byte)'o'
            };
            os.write(b,0,5);
            //不要忘记flush
            os.flush();
        }
    }
}
示例四:
public class Demo07 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os=new FileOutputStream("output.txt");) {
            String s="Hello";
            byte[]b=s.getBytes();
            os.write(b);
            //不要忘记flush
            os.flush();
        }
    }
}
示例五:
public class Demo07 {
    public static void main(String[] args) throws IOException {
        try(OutputStream os=new FileOutputStream("output.txt");) {
            String s="我爱中国";
            byte[]b=s.getBytes("UTF-8");
            os.write(b);
            //不要忘记flush
            os.flush();
        }
    }
}
追加写:

在以上代码案例中,如果我们将代码多执行几遍,期望应该是每次执行的代码都会重复地将数据写入到文件中,实际上文件里只会存在一次写入的数据。Outputstream是会清除上次文件的内容的,打开文件的一瞬间,上次的文件就被清空了。

try(OutputStream os=new FileOutputStream("output.txt",true);) {
            
        }

在创建对象时,加上一个参数“true”,就是追加写,能保证上次的数据不被清空。

(二)字符流

字符流读写文件是以字符为单位,是针对文本文件使用的。

针对读和写,有两个类:Reader和Writer类。

与字节流一样Reader和Writer都是抽象类,要实例化其子类对象FileReader和Filewriter。

字符流类的成员方法和构造方法与字节流基本一致,下面是代码案例。

1、Reader

read()和read(byte[]b)代码示例:

public class Demo08 {
    public static void main(String[] args)throws IOException {
        try(Reader reader=new FileReader("hello.txt")){
            while(true){
                int n=reader.read();
                if(n==-1){
                    break;
                }
                //n要转换成char类型
                System.out.print((char)n);
            }
        }
    }
}
public class Demo08 {
    public static void main(String[] args)throws IOException {
        try(Reader reader=new FileReader("hello.txt")){
            //建立缓冲区
            //这里是字符流,要用char类型
            char[]buf=new char[1024];
            int len;
            while(true){
                len=reader.read(buf);
                if(len==-1){
                    break;
                }
                for(int i=0;i<len;i++){
                    System.out.println(buf[i]);
                }
            }
        }
    }
}

2、Writer

public class Demo09 {
    public static void main(String[] args) throws IOException {
        try(Writer writer=new FileWriter("output.txt",true)){
            String s="我爱中国";
            writer.write(s);
            writer.flush();
        }
    }
}

二、总结

不管是字节流还是字符流,在读写文件时,代码是差不多的。

对于读入文件,在while中主要有read()和read(byte/char[]b)两种方式:

  • read()反复地读取文件,返回值n是读取到的字节数据,当n=-1时表示文件读取完成。
  • read(byte/char[]b)在read()的基础上,使用了缓存区byte/char[]b,read(byte/char[]b)将读取到的字节数据存到缓存区中,返回值len为读取到的数据个数,当len=-1时表示文件读取完成。

对于写出文件,有writer()和writer(byte/char[]b)两种方式。


网站公告

今日签到

点亮在社区的每一天
去签到