文章目录
0 IO概述
从Java代码上来看,输入流就是从外部(硬盘) 读取到内存中的,并且 以 Java的数据类型表示(byte String Int…)
处理完成这些读取来的数据
输出流 结果输出到某些地方
0.1 InputStream/OutputStream
IO字节流
IO流以byte 字节(8bit) 为最小的单位
0.2 Reader/Writer
IO字符流
需要读取的是字符,并且是多语种的(不全是单byte 的ASCII字符)
按照char来读写显然更方便,这个读取的最小单位是字符
在UTF-8 中 ,一个char :1~4 个byte
中文UTF-8中占用三个byte
GBK 中文占用 2 byte,但是只有中文和英文
UTF-8 中文占用三个
例如 Reader 数组 Hello世界,并且使用UTF-8,最终占用11个byte
hello ,英文占用一个byte
世界 ,中文每个占用三个byte
使用Reader,数据源虽然是byte,但是读入的都是char类型的字符,
原因是Reader内部做了byte的解码—>char
而使用InputStream是读取了byte 后续可以手动做转码
根据使用场景,灵活切换
0.3 同步异步
同步IO:IO时,必须等待数据返回后才能继续执行后续代码,编写简单 但是效率低 。java.io
异步IO:IO时,发出IO请求后,立即执行后续的代码,提高CPU效率 但是代码编写复杂。java.nio
1 File类的使用
- Java.io.File:文件&文件路径的抽象形式,与平台无关
- File能创建、删除、重命名文件和目录,但是File不能访问文件内容本身,需要用到IO流
- 想要在Java程序中表示一个真实存在的文件或目录,必须有一个FIle对象,但是一个java对象不一定真实存在一个文件
- File对象可以作为参数传递给contractor
File构造器
//构造器1
File file1 = new File("./data/hello.txt");
File file2 = new File("D:\\workplace\\JavaTrain\\JavaSenior\\src\\main\\java\\JavaSenior\\d09\\data\\hello.txt");
System.out.println(file1);
System.out.println(file2);
//构造器2
File file3 = new File("D:\\workplace\\JavaTrain\\JavaSenior\\src\\main\\java\\JavaSenior\\", "data");
System.out.println(file3);
//构造器3
File file4 = new File(file3, "hello.txt");
System.out.println(file4);
- 路径中每级目录之间用一个路径分隔符隔开
- 路径分隔符与系统有关
- windows DOS 用”\“来分隔
- Unix URL 用”/“来分隔
- java程序支持跨平台性,因此路径分隔符要慎重
- 为解决这个隐患 File类提供一个常量:
public static final String sqparator //根据操作系统,动态提供分隔符
1.2 常用方法
@Test
public void test3() throws IOException {
File file = new File("src/main/java/JavaSenior/d09/data/test");//Test中相对于当前Modul,Mian相对于工程
if(!file.exists()){
System.out.println(file.createNewFile());
file.mkdir();
}
System.out.println(file.getAbsolutePath());
File file2 = new File(file, "file2");
File file3 = new File(file, "file2/file3");
File file4 = new File(file, "file3/test.txt");
if(!file4.exists()){
file4.createNewFile();//createNewFile 为创建文件所用
}
}
}
2 IO流原理及流的分类
2.1 流的分类
3 节点流(或文件流)
3.1 读数据
3.1.1 fileReader
直接作用在文件之上的流
* **********流的体系结构
* 抽象基类 节点流(文件流) 缓冲流(处理流的一种)
* InputStream FileInputStream BufferedInputStream
* OutputStream FileOutPutStream BufferedOutputStream
* Reader FileReader BufferReader
* Writer FileWriter BufferWriter
/*
* 将hello.txt 内容输出到控制台(内存)
* */
@Test
public void testFileReader() throws IOException {
//TODO 1 实例化对象 指明操作的文件
File file = new File("src/main/java/JavaSenior/d09/data/hello.txt");//相较于当前modle
//TODO 2 提供具体的流
FileReader fileReader = new FileReader(file);
//TODO 3 数据的读入过程
int read = fileReader.read();//read()返回读入的一个字符。文件末尾-1
while (read != -1){
System.out.print((char)read);
read = fileReader.read();
}
//方式2
int read;
while ((read = fileReader.read()) != -1){
System.out.println((char) read);
}
//TODO 4 流的关闭操作
fileReader.close();
}
3.1.2 对read()升级
//对read()升级,使用read的重载方法
@Test
public void testFileReader1() throws IOException {
FileReader fr = null;
try {
//TODO 1 File类的实例化
File file = new File("src/main/java/JavaSenior/d09/data/hello.txt");//相较于当前modle
//TODO 2 FileReader流的实例化
fr = new FileReader(file);
//TODO 3 读入的操作
//read(char[] cbub):返回每次读入到cbuf数组中的字符个数
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) !=-1 ){
//错误写法
// for(int i = 0; i < cbuf.length ; i++){
// System.out.println(cbuf[i]);
// }
// //正确写法:
// for(int i = 0 ; i < len ; i++){
// System.out.println(cbuf[i]);
// }
//方式二:
//错误
// String s = new String(cbuf);
// System.out.println(s);
//正确
String s = new String(cbuf,0,len);
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//TODO 4 资源的关闭
fr.close();
}
3.2 写数据
@Test
public void testWriter() throws IOException {
//TODO 1 提供File类的对象,指明写出到的文件
File file = new File("src/main/java/JavaSenior/d09/data/Writer2.txt");
//TODO 2 提供一个FileWriter对象,用于写出
FileWriter fileWriter = new FileWriter(file,true);//false会覆盖原文件
//TODO 3 写出的操作
fileWriter.write("I have a dream!\n");
fileWriter.write("U have a dream!");
//TODO 4 流资源的关闭
fileWriter.close();
3.3 读入写出文件
@Test
public void testRW() throws IOException {
//TODO 1 创建File类的对象,读入和写出文件
File srcFile = new File("src/main/java/JavaSenior/d09/data/Writer2.txt");
File destFile = new File("src/main/java/JavaSenior/d09/data/Writer3.txt");
//TODO 2 创建输入流 和 输出流的对象
FileReader fr = new FileReader(srcFile);
FileWriter fw = new FileWriter(destFile);
//TODO 3 数据读入和写出操作
try {
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中的字符的个数
while ((len = fr.read(cbuf)) != -1){
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//TODO 4 关闭资源
fw.close();
fr.close();
}
3.4 图片的写入写出
@Test
public void photoRW() throws IOException {
//todo 1 文件对象
File srcFile = new File("src/main/java/JavaSenior/d09/data/LOL.PNG");
File destFile = new File("src/main/java/JavaSenior/d09/data/PHOTO2.PNG");
FileInputStream is = null;
FileOutputStream os = null;
try {
//todo 2 创建字节流
is = new FileInputStream(srcFile);
os = new FileOutputStream(destFile);
//todo 3 写入写出
byte[] buf = new byte[1024];
int len;
while (-1 != (len = is.read(buf))){
os.write(buf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//todo 4 关闭资源
is.close();
os.close();
}
4 缓冲流
提高数据读取速度,Java提供了带换成功能的流,会创建一个内部缓冲区数组,缺省8192个字节(8kb)缓冲区
@Test
public void BufferedStreamTest() throws IOException {
//TODO 1 文件
File srcFile = new File("src/main/java/JavaSenior/d09/data/hello.txt");
File descFile = new File("src/main/java/JavaSenior/d09/data/hello22.txt");
//TODO 2 节点流
FileInputStream fileInputStream = new FileInputStream((srcFile));
FileOutputStream fileOutputStream = new FileOutputStream((descFile));
// todo 2.2 缓冲流
BufferedInputStream bis = new BufferedInputStream(fileInputStream);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
//TODO 3 复制的细节:读取、写入
byte[] buffer = new byte[10];
int len;
while (-1 != (len = bis.read(buffer))){
bos.write(buffer,0,len);
bos.flush();//不满的话也写出去
}
//TODO 4 资源关闭
bos.close();
bis.close();
//外层关闭之后,内层也会直接关闭
// fileOutputStream.close();
// fileInputStream.close();
5 转换流(装换流)
字节流 & 字符流之间的转换
- InputStreamReader:将InputStream转换为Reader
- OutputStreamWriter:将Writer转换为OutputStream
字节流中的数据都是字符时,转换成字符流更加高效
转换流尝试解决乱码问题,实现编码&解码功能
@Test
public void test() throws IOException {
File file = new File("src/main/java/JavaSenior/d09/data/hello.txt");
FileInputStream fis = new FileInputStream(file);
//参数2指明字符集,
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");//使用系统默认的字符集
char[] chars = new char[1024];
int len;
while (-1 != (len = isr.read(chars))){
String s = new String(chars, 0, len);
System.out.println(s);
}
isr.close();
5.2 字符集
6 标准输入、输出流
7 打印流
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
ps = new PrintStream(fos, true);
if (ps != null) {// 把标准输出流(控制台输出)改成文件
System.setOut(ps);
}
for (int i = 0; i <= 255; i++) { // 输出ASCII字符
System.out.print((char) i);
if (i % 50 == 0) { // 每50个数据一行
System.out.println(); // 换行
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
}
8 数据流
9 对象流
9.1 序列化的理解
- 对象序列化机制:把内存中的java对象----- 序列化 --> 二进制流 ,从而允许这种二进制流保存在磁盘上,或传输到另外网络节点 ,其他节点 ------反序列化-------> Java对象
- 序列化可以将任何实现了Serializable接口的对象---------->字节数据,
- 序列化是RMI(Remote Method Invoke) 过程参数&返回值都必须有的机制,序列化 --> RMI —> JavaEE
- 对象可序列化 —> 对象的类 对象的属性 都可序列化 。 类序列化 —> Serializable Externalizable 接口
9.2 使用对象流序列化对象
/*
* 序列化过程:内存对象存储到磁盘
* ObjectOutputStream使用
* */
@Test
public void testObjectOutputStream() throws IOException {
ObjectOutputStream oops = new ObjectOutputStream(new FileOutputStream("object.txt"));
oops.writeObject(new String("hello world"));
oops.flush();
oops.close();
}
/*
反序列化:从文件中的数据还原为内存中的对象
* */
@Test
public void testObjectInputStream() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
Object o = ois.readObject();
String str = (String) o;
System.out.println(str);
ois.close();
}
9.3 对象可序列化
1 . 需要实现Serializable接口
2 . 需要当前类提供一个全局常量serialVersionUID
ObjectOutputStream和ObjectInputStream不能序列化static和transient修
饰的成员变量
10 随机存取文件流
/*
直接继承与Object ,实现了DataInput 、DataOutput接口
* 2.姐可以作为一个输入流,又可以作为一个输出流
3. 如果Random文件已经存在,从头覆盖
* */
public class RandomAccessFileTest {
@Test
public void test1() throws IOException {
RandomAccessFile randomAccessFile1 = new RandomAccessFile(new File("src/main/java/JavaSenior/d09/data/hello.txt"),"r");
RandomAccessFile randomAccessFile2 = new RandomAccessFile(new File("src/main/java/JavaSenior/d09/data/helloR.txt"),"rw");
byte[] bytes = new byte[1024];
int len;
while ((len = randomAccessFile1.read(bytes)) != -1 ){
randomAccessFile2.write(bytes,0,len);
}
randomAccessFile1.close();
randomAccessFile2.close();
}
}
11 NIO2中Path、Paths File类的使用
11.1 NIO
New IO, Non-Blocking IO从Java1.4开始引入的一套新的IO API,可以替代标准版的Java IO API
NIO将以更加高效的方式进行文件的读写操作 ,NIO支持面向缓冲区,IO支持面向流的
随着 JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对
文件处理和文件系统特性的支持,以至于我们称他们为 NIO.2。
因为 NIO 提供的一些功能,NIO已经成为文件处理中越来越重要
的部分。
11.2 Path Paths Files 核心API
commons.io
public class FileUtilsTest {
public static void main(String[] args) throws IOException {
File file1 = new File("JavaSenior/src/main/java/JavaSenior/d09/data/hello.txt");
File file2 = new File("JavaSenior/src/main/java/JavaSenior/d09/data/commonsIO.txt");
FileUtils.copyFile(file1,file2);