文章目录
前言
IO操作:
- 文件操作——文件IO(对硬盘上的文件进行操作)
- 网络IO: 网络通信,接收数据: 主机网卡接收到数据,转发到对应端口(url中包含端口字段),由进程来接收;发送数据: 进程把发送的数据,转发到对应端口,再发送到网卡,再发送到远程主机
我之前写到web开发,学习Servlet的时候
request中,包含了IO的输入流
response中,包含了IO的输出流
IO从不同的维度,可以划分为不同类型的IO:
- 从流向: 输入流:接收数据;输出流:向其他设备输出数据
- 从数据类型: 文本(字符流):接受或发送字符串;二进制(字节流):接受或发送二进制数据
在计算机底层来看:其实都是发送的二进制数据
文本只是一种包含了编码格式的二进制数据,是可以和二进制数据互相转换的:
String转字节: str.getBytes(“utf-8”);
字节转String: new String(bytes,“utf-8”);
把二进制数据转换为字符串,如果是乱码:
(1)本身就不是文本类型的数据,如图片
(2)如果是文本类型转换的二进制数据,那么编码和解码的格式要一致才行:如按gbk把文本转为二进制,也要使用gbc来转文本(否则就会出现乱码)
一、IO的特性
- 对于输入流来说,已经读取过的数据不能再次读取
- 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");
注意事项:
- JDK提供的File,既包含文件,也包含目录
- 文件url,分隔符可以写斜杠或反斜杠(JDK底层是会根据操作系统转换为对应的系统路径分隔符)
- 如果传入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效率高一点):
- 读取到一个字节输入流:如FileInputStream
- 使用字节字符输入转换流:InputStreamReader(可以转换字节流为字符流,并且可以设置编码)
- 使用字符输入流:如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] | 写一个字节 |
使用注意事项:
- 输出:写数据
- 刷新
- 关闭
缓冲区:输入和输出都是在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();
//关闭
}
}