Java 流(Stream)、文件(File)和IO

一、I/O原理

  • 文件是数据源,在程序中以流(Stream)的形式存在。
  • I/O是Input和Output的缩写,I/O技术是非常实用的技术,用于处理数据传输(如:读/写文件,网络通信)。
  • Java程序中,对于数据的输入/输出操作是以流(stream)的方式进行的。
  • java.io 包是 Java 标准库中的一个核心包,提供了用于系统输入和输出的类,它包含了处理数据流(字节流和字符流)、文件读写、序列化以及数据格式化的工具。
    在这里插入图片描述

一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。

二、I/O流的分类

  • 按操作数据单位分为:字节流(二进制文件)、字符流(文本文件)
  • 按数据的流向分为:输入流、输出流
  • 按流的角色分为:节点流、处理流

三、流的分类

下图是一个描述输入流和输出流的类层次图
在这里插入图片描述

分类字节输入流字节输出流字符输入流字符输出流
抽象基类InputStreamOutputStreamReaderWriter
访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter
访问管道PipedInputstreamPipedOutputStreamPipedReaderPipedWriter
访问字符串StringReaderStringWriter
缓冲流BufferdInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
转换流InputStreamReaderOutputStreamWriter
对象流ObjectInputStreamObjectOutputStream
过滤流FilterInputStreamFilterOutputStreamFilterReaderFilterWriter
打印流PrintStraeamPrintWriter
推回输入流PushbackInputStreamPushbackReader
数据流DateInputStreamDataOutputStream

四、字节流

1. 字节流写数据

方法名描述
void write(int b)将指定的字节写入输出流,b 的低 8 位将被写入流中
void write(byte[] b)将字节数组 b 中的所有字节写入输出流 一次写一个字节数组数据
void write(byte[] b,int off,int len)将字节数组 b 中的所有字节写入输出流 一次写一个字节数组的部分数据
void flush()刷新输出流并强制写出所有缓冲的数据,确保数据被立即写入目标输出
void close()关闭输出流并释放与该流相关的所有资源。关闭后不能再写入

使用字节输出流写数据的示例:

public class FileOutputStreamTest1 {
    public static void main(String[] args) throws IOException {
        // 步骤一:创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
        File file = new File("file.txt");
        FileOutputStream fos = new FileOutputStream(file);
        // 步骤二:调用字节输出流对象的写数据方法
        fos.write(97);
        // 步骤三:释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
        fos.close();
    }
}
 

2. 字节流读数据

方法描述
int read()读取一个字节的数据,返回值为 0 到 255 之间的整数。如果到达流的末尾,返回 -1
int read(byte[] b)从输入流中读取字节,并将其存储在字节数组 b 中,返回实际读取的字节数。如果到达流的末尾,返回 -1
int read(byte[] b, int off, int len)从输入流中读取最多 len 个字节,并将它们存储在字节数组 b 的 off 偏移位置,返回实际读取的字节数。如果到达流的末尾,返回 -1
long skip(long n)跳过并丢弃输入流中的 n 个字节,返回实际跳过的字节数
int available()返回可以读取的字节数(不阻塞)
void close()关闭输入流并释放与该流相关的所有资源
void mark(int readlimit)在流中的当前位置设置标记,readlimit 是可以读取的字节数上限
void reset()将流重新定位到上次标记的位置,如果没有标记或标记失效,抛出 IOException
boolean markSupported()检查当前输入流是否支持 mark() 和 reset() 操作

使用字节输入流读取数据的示例:

一次读一个字节字符数据

public class FileInputStreamTest1 {
    public static void main(String[] args) throws IOException {
        // 步骤一:创建字节输入流对象
        FileInputStream fis = new FileInputStream("file.txt");
        int file = 0;
        // 步骤二、调用字节输入流对象的读数据方法
        while((file=fis.read())!=-1){
            System.out.print((char)file);
        }
        // 步骤三、释放资源
        fis.close();
    }
}

一次读一个字节数组数据

public class FileInputStreamTest2 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("file.txt");
        byte[]bytes = new byte[1000];
        int length = 0;
        while((length=fis.read(bytes))!=-1){
            System.out.print(new String(bytes,0,length));
        }
        fis.close();
    }
}

五、字符流

1. 字符流写数据

字符流写数据的5种方式

方法描述
void write(int c)写入一个字符c
void write(String str)写入一个字符串
void write(String str,int off,int len)写入字符串的一部分,off偏移量,len长度
void write(char[] cbuf)写入一个字符数组
void write(char[] cbuf,int off,int len)写入字符数组的一部分,off偏移量,len长度

刷新和关闭的方法

方法说明
flush()刷新流,之后还可以继续写数据
close()关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据

2. 字符流读数据

字符流读数据的两种方式

方法名描述
int read()从输入流中读取字符,一次读取一个字符数据
int read(byte[] b)一次读取一个字符数组数据

六、解决乱码问题——字节与字符的转化

数据持久化或网络传输都是以字节进行的,所以必须要有字符到字节或字节到字符的转化。

1. 字符流中的编码解码问题

  • InputStreamReader 类是字节到字符的转化桥梁,InputStream 到 Reader 的过程要指定编码字符集,否则将采用操作系统默认字符集,很可能会出现乱码问题。StreamDecoder 正是完成字节到字符的解码的实现类。
  • OutputStreamWriter 是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节,由StreamEncoder完成编码过程。
//文件名 :fileStreamTest2.java
import java.io.*;
 
public class fileStreamTest {
    public static void main(String[] args) throws IOException {
 
        File f = new File("a.txt");
        FileOutputStream fop = new FileOutputStream(f);
        // 构建FileOutputStream对象,文件不存在会自动新建
 
        OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
        // 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
 
        writer.append("中文输入");
        // 写入到缓冲区
 
        writer.append("\r\n");
        // 换行
 
        writer.append("English");
        // 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入
 
        writer.close();
        // 关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉
 
        fop.close();
        // 关闭输出流,释放系统资源
 
        FileInputStream fip = new FileInputStream(f);
        // 构建FileInputStream对象
 
        InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
        // 构建InputStreamReader对象,编码与写入相同
 
        StringBuffer sb = new StringBuffer();
        while (reader.ready()) {
            sb.append((char) reader.read());
            // 转成char加到StringBuffer对象中
        }
        System.out.println(sb.toString());
        reader.close();
        // 关闭读取流
 
        fip.close();
        // 关闭输入流,释放系统资源
 
    }
}

2. 字符串中的编码解码问题

  • 编码:byte[] getBytes(String charsetName)使用指定的字符集将该 String编码为一系列字节,无指定则使用平台的默认字符集。\
  • 解码:String(byte[] bytes, String charsetName)通过指定的字符集解码指定的字节数组来创建字符串,无指定则使用平台的默认字符集。

七、字符缓冲流

1. BufferedWriter

将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途。

方法void newLine() 写一行行分隔符。 行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符(‘\ n’)字符。

2. BufferedReader

从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。

方法String readLine() 读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾。

八、文件目录

1.创建目录

  • mkdir( )方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
  • mkdirs()方法创建一个文件夹和它的所有父文件夹。
import java.io.File;
 
public class CreateDir {
    public static void main(String[] args) {
        String dirname = "/tmp/user/java/bin";
        File d = new File(dirname);
        // 现在创建目录
        d.mkdirs();
    }
}

2.读取目录

一个目录其实就是一个 File 对象,它包含其他文件和文件夹。

如果创建一个 File 对象并且它是一个目录,那么调用 isDirectory() 方法会返回 true。

可以通过调用该对象上的 list() 方法,来提取它包含的文件和文件夹的列表。

3.删除目录或文件

删除文件可以使用 java.io.File.delete() 方法。

需要注意的是当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值