关于文件操作和IO


前言

IO操作:

  1. 文件操作——文件IO(对硬盘上的文件进行操作)
  2. 网络IO: 网络通信,接收数据: 主机网卡接收到数据,转发到对应端口(url中包含端口字段),由进程来接收;发送数据: 进程把发送的数据,转发到对应端口,再发送到网卡,再发送到远程主机

我之前写到web开发,学习Servlet的时候
request中,包含了IO的输入流
response中,包含了IO的输出流

IO从不同的维度,可以划分为不同类型的IO:

  1. 从流向: 输入流:接收数据;输出流:向其他设备输出数据
  2. 从数据类型: 文本(字符流):接受或发送字符串;二进制(字节流):接受或发送二进制数据

在计算机底层来看:其实都是发送的二进制数据
文本只是一种包含了编码格式的二进制数据,是可以和二进制数据互相转换的:
String转字节: str.getBytes(“utf-8”);
字节转String: new String(bytes,“utf-8”);

把二进制数据转换为字符串,如果是乱码:
(1)本身就不是文本类型的数据,如图片
(2)如果是文本类型转换的二进制数据,那么编码和解码的格式要一致才行:如按gbk把文本转为二进制,也要使用gbc来转文本(否则就会出现乱码)

一、IO的特性

  1. 对于输入流来说,已经读取过的数据不能再次读取
  2. JDK中,IO的api,是以包裹的方式来组装:new 水管输入流(new 净水器过滤输入流())

二、Java中操作文件

1.File概述

属性:

//不重要:path环境变量的分隔符:windows是分号(;),linux是(:)
System.out.println(File.pathSeparator);
//url路径的分隔符:windows是反斜杠(\) linux是斜杠(/)
System.out.println(File.separator);

计算机底层,windows路径必须是\,linux必须是/
Java语言,是有路径分隔符转换的:所以写代码,windows路径写/也没事

//反斜杠是转义,所以写两个:也可以写 斜杠(/)
File f1 = new File("D:\\StudyJava\\Jmeter.png");

注意事项:

  1. JDK提供的File,既包含文件,也包含目录
  2. 文件url,分隔符可以写斜杠或反斜杠(JDK底层是会根据操作系统转换为对应的系统路径分隔符)
  3. 如果传入File的路径不存在,其实还是创建了File对象,只是exist()=false

常用API:

API[返回值]功能
exists() [boolean]文件或目录是否存在
getName() [String]返回目录或文件的名称
getPath() [String]返回路径
isDirectory() [boolean]是否是目录
isFile() [boolean]是否是文件
listFiles() [File[]]返回目录下一级的子文件或子文件夹
mkdir() [boolean]创建目录
mkdirs() [boolean]创建多级目录
createNewFile() [boolean]创建文件
delete() [boolean]删除

三、文件内容的读写——数据流

  • 类名包含Stream:字节流
  • 包含Input:输入流
  • 包含Output:输出流
  • 包含Reader:字符输入流
  • 包含Writer:字符输出流
  • 包含File:做文件操作的流

1.InputStream概述

抽象类(字节输入流)

API [返回值]功能
read() [abstract int]读取一个字节,返回值是读取的数据:返回-1,表示读取到最后
read(byte[] b) [int]把数据读取到字节数组中:如果数据超过b的长度,也只读b长度的数据;如果数据没有b那么长,就只读可以获取的有效的长度(b数组中,部分读取到)
read(byte[] b,int off,int len) [int]把数据读取到字节数组中,从off开始,读len的长度,返回读取的长度
close() [void]关闭流:使用完IO流一定要关闭

JDBC操作中,Connection、Statement、ResultSet对象,其实都包含了IO流
所以使用完都要关闭,且关闭的顺序和创建顺序相反

web开发时,request、response也包含IO流,但我们没有在Servlet中关闭?
tomcat在返回响应以后(根据response构造http响应的数据包),会自动的关闭response和request

2.FileInputStream概述

用于文件读取
构造方法:

签名说明
FileInputStream(File file)利用File构造文件输入流
FileInputStream(String name)利用文件路径构造文件输入流

注意:该路径文件必须存在,否则会报错——和File使用不同的地方

使用总结:
1.一个字节一个字节读,返回值就是读取的数据,如果是-1,表示读取到最后
在这里插入图片描述
2.读取到字节数组中,数据是在字节数组中,返回值是读取的长度(如果返回-1,表示读取到最后)
在这里插入图片描述
另外:JDK1.8,提供了一种自动关闭流的方式

try(某个流){
	...
}

执行完,会自动调用流.close()关闭

3.利用Scanner进行字符读取

Scanner:内部包含/保存了输入流对象

API [返回值]功能
next() [String]读取下一个字符串(读到空格,换行符或其他)
nextInt() [int]读取到下一个int整数
nextLine() [String]读取下一行(读取到下一个换行符)

4.输入流总结

二进制数据读取:
FileIntputStream:文件字节输入流
BufferedInputStream:缓冲的字节输入流(相对来说,效率高一点

public class Api_二进制数据读取 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:\\StudyJava\\Jmeter.png");
        //使用BufferedInputStream读取速度更快一点
        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] bytes = new byte[1024];
        int len;
        while((len=bis.read(bytes))!=-1){
            //此时,bytes[0,len]就是读取的数据
            //图片是非文本的,转成字符串也是乱码
        }
        //关闭掉
        bis.close();
        fis.close();
    }
}

文本类型的数据读取(FileReadwer也可以,操作更简单,但BufferedReader效率高一点):

  1. 读取到一个字节输入流:如FileInputStream
  2. 使用字节字符输入转换流:InputStreamReader(可以转换字节流为字符流,并且可以设置编码)
  3. 使用字符输入流:如BufferedReader
public class Api_文本数据读取 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("D:/Gitee/1.txt");
        //先使用字节字符转换流
        InputStreamReader isr = new InputStreamReader(fis);
        //再使用字节输入流
        BufferedReader br = new BufferedReader(isr);
        //br.readLine: 一行一行的读取,如果返回null,表示读取到最后
        String line;
        while((line=br.readLine())!=null){
            System.out.println(line);
        }
        //关闭
    }
}

5.OutputStream概述

字节输出流

API [返回值]功能
close() [void]关闭流
flush() [void]刷新缓冲区
write(byte[] b) [void]写整个字节数组
write(byte[] b,int off,int len) [void]写数组[off,off+len]
write(int b) [abstract void]写一个字节

使用注意事项:

  1. 输出:写数据
  2. 刷新
  3. 关闭

缓冲区:输入和输出都是在Java进程中,开辟了一块缓冲区,来存放数据,读写完再一次性刷新缓冲区(读、或写)

6.FileOutputStream概述

写二进制数据

构造方法:
FileOutputStream(File file,boolean append)
append为true,就是以追加的方式,添加到文件原有数据的尾部

public class Api_FileOutputStream {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("D:/Gitee/1.txt");
//        fos.write(new byte[]{1,2,3,4});//这样写字节数据,就是乱码
        //写文本: 和文本保存编码格式要一致
        fos.write("点击".getBytes(StandardCharsets.UTF_8));
        fos.flush();
        fos.close();
    }
}

BufferedOutputStream: 缓冲的字节输出流(效率相对更高)

public class Api_BufferedOutputStream {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("D:/Gitee/1.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        //写文本: 和文本保存编码格式要一致
        bos.write("点击".getBytes(StandardCharsets.UTF_8));
        bos.flush();
        bos.close();
    }
}

二进制输出流写文本就不太方便

写文本类型的数据
FileWriter: 类似FileReader,比较简单
BufferedWriter: 缓冲的字符输出流

public class Api_BufferedWriter {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("D:/Gitee/1.txt");
        //要使用字符输出流,先要使用字节字符转换流
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
        //再使用字符输出流
        BufferedWriter bw = new BufferedWriter(osw);
        bw.write("哈哈\n");//自己加换行符,或使用bw.newLine()来换行
        bw.write("好了");
        //刷新缓冲区
        bw.flush();
        //关闭
    }
}

PrintWriter:

public class Api_PrintWriter {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("D:/Gitee/1.txt");
        //要使用字符输出流,先要使用字节字符转换流
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
        //再使用字符输出流
        PrintWriter pw = new PrintWriter(osw);
        pw.println("哈哈");//自己加换行符,或使用bw.newLine()来换行
        pw.println("好了");
        //刷新缓冲区
        pw.flush();
        //关闭
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dhdhdhdhg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值