文章目录
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是IO流
IO流值得是 输入流(Input stream),输出流/(Ouput stream)的简称,是计算机程序用于处理输入和输出的一种抽象的概念
Input Stream 输入流
输入流的层次结构
- InputStream(字节输入流):所有输入流的父类,提供了读取子节点的基本方法,Read(字符输入流):用于读取字符数据的抽象类 继承自InputStreamReader
- FileInputStream:用于文件进行读取数据的输入流
- ByteArrayInputStream:从字节数组中读取数据的输入流
- DataInputStream :处理流更改构造方法接收一个已经存在的输入流
- FileReader:从文件中读取字符数据的输入流
- StringReader:从字符串中的读取字符数据的输入流
- BufferedReader :字符缓冲输入流
- InputStreamReader :接受字节输入流并使用指定的字符集将其解码成字符
- BufferedInputStream :缓冲字节输入流
Files.newInputStream和FileInputStream
- Files.newInputStream流和FileInputStream的区别
- Files.newInputStream是jdk1.7引入的属于(New I/O 2)部分,而FileInputStream是属于传统的I/O流类库,从比较早的版本到现在一直都存在
- API设计:FileInputStream属于传统的API相对简单一点而Files.newInputStream有着更高的特性
- Files.newInputStream更高的特性体现于可以灵活的路径处理,它的参数是Path对象,并不是直接的文件路径字符串,这也就意味着可以使用更灵活的路径操作
列子: 两种运用方式
- Files.newInputStream更高的特性体现于可以灵活的路径处理,它的参数是Path对象,并不是直接的文件路径字符串,这也就意味着可以使用更灵活的路径操作
try (InputStream inputStream = Files.newInputStream(Paths.get("path.xml"))) {
// 读取数据的逻辑
} catch (IOException e) {
e.printStackTrace();
}
又或者
Path path=Paths.get("path.xml");
try (InputStream inputStream = Files.newInputStream(path)) {
// 读取数据的逻辑
} catch (IOException e) {
e.printStackTrace();
}
更多的文件操作的方法,比如Files.copy,Files.Move
列子: 将源文件复制到目标文件
try {
Files.copy(Paths.get("path.txt"), Paths.get("test.txt"));
} catch (IOException e) {
e.printStackTrace();
}
支持更多的选项:StandardOpenOption.READ,StandardOpenOption.WRITE等一系列的选项用于打开文件的指定方式,提供了更多的控制性跟灵活性差
Path path=Paths.get("path.xml");
try (InputStream inputStream = Files.newInputStream(path,StandardOpenOption.CREATE)) {
} catch (IOException e) {
e.printStackTrace();
}
-
- 异常的处理机制
- FileInputSteram主要抛出FileNotFoundException和IOException
- Files.newInputStream使用的是NOI.2的异常体系可以抛出IOException和UncheckedIoexception等一系列异常
- 实现原理:
- Files.newInputSteram是用过NIO.2中的FileChannel和ByteBuffer实现的,他提供了更灵活更高效的文件I/O的操作,允许对文件进行更多的控制
- FileInputStream是使用传统的InputStream类库,底层通过本地的文件系统调用实现,较为简单直接从文件输入流中读取字节
- 优缺点:
- Files.newInputStream:灵活,异常体系更丰富,对于简单的文件读取任务显得有些过于复杂
- FileInputStream:对于简单的读取使用起来比较简单直接,就是功能在文件I/O的操作上有相对的限制
- 文件流读取的几种实现方式
- 异常的处理机制
//缓冲流读取,它提供了缓冲区来提高读取的性能。通过包装其他输入流,
try (BufferedInputStream bufferedInput = new BufferedInputStream(Files.newInputStream(Paths.get("example.txt")))) {
int data;
while ((data = bufferedInput.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// Scanner 类可以方便地用于读取各种数据类型,包括基本类型和字符串
try (Scanner scanner = new Scanner(new FileInputStream("example.txt"))) {
while (scanner.hasNext()) {
String data = scanner.next();
System.out.println(data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//从底层输入流中读取基本java数据类型
Path path = Paths.get("example.txt");
try (DataInputStream dataInput = new DataInputStream(Files.newInputStream(path))) {
int data = dataInput.readInt();
System.out.println(data);
} catch (IOException e) {
e.printStackTrace();
}
//是用于读取字符流的类,可以用于读取字符文件的内容
try (FileReader fileReader = new FileReader("example.txt")) {
int data;
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
//字符输入流的缓冲,它提供了缓冲区来提高读取字符的性能
try (BufferedReader bufferedReader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayInputStream 流
- ByteArrayInputStream 是java中的InputStream的一个具体实现,他是从字节数组中读取数据,允许程序已流的方式从内存中的字节数组中读取数据,不需要实际的物理文件或者是网络链家
public class ByteArrayInputStream extends InputStream {
/**
* 使用整个字节数组作为输入流
* buf要读取的字节数组
*/
public ByteArrayInputStream(byte[] buf)
/**
* 使用指定区域的字节数组作为输入流
* buf要读取的字节数组
* offset 字符数组的起始偏移量
* length 要读取的字符数
*/
public ByteArrayInputStream(byte[] buf, int offset, int length)
}
- ByteArrayInputStream提供了一些方法
- read()读取下一个字节
- read(byte[]n,int off,int len):从输入流中读取最多len个字节到字节数组b中 从偏移量off开始存储,返回实际读取的字符数
- skip(long n ):n就是代表要跳过的数组
- available():可以从此输入流中读取或跳过 而不会阻塞的剩余字符数
- 实现原理:ByteArrayInputStream是通过字节数组包装秤输入流的方式实现,其内部维护了一个字节数组,通过指针来记录当时读取的位置,在调用读取方法的时候,他会从字节数组中读取相应的数据,并且更新指针位置
- 优缺点:
- 适用于内存中的数据操作 无需依赖外部的文件网络等
- 他是基于字节数组实现的 相对其他输入流来说ByteArrayInputStream 是一个轻量级的存在
- 他依赖于一个固定的字节数组,不适用于动态数组或者大型的数据流
- 一旦字节数组传递给ByteArrayInputStream它的内容就没有办法进行实现了
- 不支持标记和重置操作
- 读取方式
//单一读取
ByteArrayInputStream inputStream = new ByteArrayInputStream(new byte[1024]);
int data;
while ((data = inputStream.read()) != -1) {
// 处理读取到的字节数据
System.out.print((char) data);
}
// 关闭输入流
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
//批量读取
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer, 0, 1024)) != -1) {
// 处理读取到的字节数组数据
System.out.print((char) bytesRead);
}
// 关闭输入流
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
DataInputStream 处理流
- DataInputStream 是java中FilterInputStream类的一个具体实现,用于从输入流中读取基本数据类型,提供了一系列的方法,可以方便的读取不同类型的数据,不需要进行手动数据类型转换
- 实现原理:DataInputStream是一个装饰器Decorator类 它继承与FilterInputStream 并且实现了DateInput的接口,主要就是对底层的输入流进行包装,他是通过调用基础的输入流读取的方法 然后根据需要将字节数据类型转换为对应的基本数据类型
- 优缺点:
- 方便的读取基本的数据类型,避免了手动进行字节到数据类型的转换
- 适用于数据序列化,提供的方法可以方便的读取和处理数据
- 异常的处理方式比较简单 具体的错误格式需要额外处理
- 他主要使用与读取基本数据类型 不太适合复杂的数据类型
- 具体实现
try (DataInputStream dataInputStream = new DataInputStream(Files.newInputStream(Paths.get("file.txt")))) {
// 读取不同类型的数据
boolean booleanValue = dataInputStream.readBoolean();
byte byteValue = dataInputStream.readByte();
char charValue = dataInputStream.readChar();
double doubleValue = dataInputStream.readDouble();
float floatValue = dataInputStream.readFloat();
int intValue = dataInputStream.readInt();
long longValue = dataInputStream.readLong();
short shortValue = dataInputStream.readShort();
String stringValue = dataInputStream.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
FileReader
- FileReader主要提供了一些用于读取字符的方法 最常用的是read用于读取单个字符
- 实现原理:基于底层的输入流,它使用了默认的字符编码或者指定的字符编码从文件中读取,在底层中使用了FileInputStream来进行读取字节 然后将字节转为字符
- 优缺点:
- 简单容易使用,适合读取文本文件
- 默认情况下 他是用的系统默认的字符编码 这就导致跨平台可能会有字符棉麻的问题,如果需要指定字符编码建议使用带有字符集的构造方法,不太适合处理二进制数据
- 读取方式
try (FileReader fileReader = new FileReader("file.txt")) {
int data;
while ((data = fileReader.read()) != -1) {
char character = (char) data;
//输出处理到的数据
System.out.print(character);
}
} catch (IOException e) {
e.printStackTrace();
}
StringReader:
- StringReader继承于Reader,方便快捷的将字符串写进内存
- 实现原理:StringReader他是基于Reader抽象类的一个具体实现 在内部它使用一个指针来追踪读取的位置,然后通过相应的方法将字符提供给调用者
- 优缺点:
- 方便的读取字符串,不涉及文件系统的操作,适用于读取纯字符串的读取场景
- 无法处理大批量数据,对大批量数据处理可能会导致内存消耗比较大
- 具体实现
String inputString = "Hello, StringReader,how are you doing!";
try (StringReader stringReader = new StringReader(inputString)) {
char[] buffer = new char[10];
int bytesRead;
while ((bytesRead = stringReader.read(buffer, 0, buffer.length)) != -1) {
// 打印读取到的字符数组数据
System.out.print(new String(buffer, 0, bytesRead));
}
} catch (IOException e) {
e.printStackTrace();
}
BufferedReader
- 实现原理:
- BufferedReader的实现主要基于字符输入流Reader 他在内部维护一个字符缓冲流 当调用read() 或readLine()方法时首先先从缓冲里边读取数据,如果缓冲区为空,则从底层Reader读取一批字符到缓冲区,然后再从缓冲区返回数据
- 优缺点
- 缓冲机制可以提高读取的性能,减少底层的读取次数 提供了方便的readLine()方法可以逐行读取文本数据
- 不适合二进制数据,他主要用于文本数据
String fileName = "file.txt";
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
// 打印读取到的行数据
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
InputStreamReader
- 实现原理:主要就是基于inputStream 在内部它使用了Charset进行处理字符编码的转换 再调用read方法的时候 他会从底层的输入流读取字节数据 然后根据指定的字符集解码为字符
- 主要提供了方便的字符编码转换,将字节流转换成了字符流 解决了字符集不一致的问题,比较适合多语言的环境,但是在进行字符编码转换的会带来一定的开销,在大批量的数据情况下开销会更大
- 代码实现
String fileName = "file.txt";
try (InputStream inputStream = Files.newInputStream(Paths.get(fileName));
//指定字符集 将流放到 InputStreamReader中
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
//转成字符流
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
String line;
while ((line = bufferedReader.readLine()) != null) {
// 处理读取到的行数据
System.out.println(line);
}
} catch (IOException e) {
log.info(e.getMessage());
}
BufferedInputStream
- BufferedInputStream是缓冲字节输入流 他提供了对底层输入流的缓冲功能,可以显著提高读取性能,他是继承自FilterInputStream包装了其他的输入流 并且添加了缓冲功能
- 实现原理:BufferedInputStream树妖基于底层的InputStream 他在内部维护了一个字节缓冲区(Byte[]数组) 当调用read方法时 首先从缓冲区读取数据,如果缓冲区数据为空则从底层的输入流中读取一批字节到缓冲区,然后再从缓冲区返回数据,这种机制可以减少对底层输入流的实际读取次数,从而提高性能
- 优缺点:
- 缓冲机制可以显著提高读取性能,减少底层读取次数,适用于大批量数据或者网络数据流,可以一次性读取较大的字节数组
- 对实时更新要求较高的不太实用,缓冲区的引入可能会导致数据的延迟
- 代码实现
String fileName = "file.txt";
try (InputStream inputStream = Files.newInputStream(Paths.get(fileName));
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
// 处理读取到的字节数组数据
System.out.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
log.info(e.getMessage());
}
OutputStream
输出流的层次结构
- 字节输出流(Byte Output Stream) 和字符输出流(cHARACTER Output Stream)
- FileOutputStream :文件输出
- DataOutputStream:输出流基本数据类型的写入
- BufferedOutputStream:通过包装其他的字节输出流,提供了缓冲功
- ByteArrayInputStream:从字节数组中读取数据
- OutputStreamWriter:字节流到字符流的桥梁,将字节流转换为字符流
- FileWriter:写入字符文件的便利类
- BufferedWriter:用于写入字符数据的缓冲字符输出流
- StringWriter:字符数据写入该缓冲区
FileOutPutStream
- FileOutPutStream:继承于OutputStream 提供了一些写入字节数据的方法,fileOutputStream实现基于底层的文件输出流,通过底层的文件系统api时间线将自己写入文件,再底层使用了FIleDescriport和本地系统调用来进行实现文件的写入
- 优缺点:
- FileOutputStream提供了灵活的方法,可以方便的将字节数组,单个字节或者部分字节,比较适合处理大文件
- 针对文本的处理需要额外的字符编码操作,,不太适合用于处理字符
- 在处理异常的时候需要额外的代码,容易忽略文件的关闭操作,最好是使用try异常处理机制,使用完确保正确的关闭流
- 代码实现
try (FileOutputStream fileOutputStream = new FileOutputStream("file.txt")) {
// 写入字节数组
byte[] data = "Hello, FileOutputStream!".getBytes();
fileOutputStream.write(data);
// 刷新并关闭流
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
DateOutputStream
- 实现原理:他通过底层的输出流实现对基本数据类型的写入,在写入的时候会将java的基本数据类型转为数组,并通过底层的输出流写入这些字节数组
- 优缺点
- 方便写入基本数据类型,可以方便的将基本数据类型以一定的格式写入输出流量,适用于与其他系统做的数据交换
- 不太适用于文本数据,因为他主要设计是用于写入基本数据类型的
try (DataOutputStream dataOutputStream = new DataOutputStream(Files.newOutputStream(Paths.get(fileName)))) {
// 写入基本数据类型
dataOutputStream.writeInt(42);
dataOutputStream.writeDouble(3.14);
dataOutputStream.writeUTF("Hello, DataOutputStream,how are you doing!");
// 刷新并关闭流
dataOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
BufferedOutputStream
- BufferedOutputStream的实现主要基于底层的输出流,在内部维护了一个字节缓冲区,当调用write方法的时候,会首先将数据写入缓冲区中,当缓冲区或者是手动调用flush方法时才会将缓冲区的数据写入底层的输出流
- 优缺点
- 缓冲机制可以显著的提高写入的性能,减少实际的底层写入的次数,适用于处理大文件或者网络数据流
- 缓冲区的引入可能会造成数据的演出
try (OutputStream outputStream = Files.newOutputStream(Paths.get("file.txt"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
byte[] data = "Hello, BufferedOutputStream!".getBytes(); bufferedOutputStream.write(data);
// 刷新并关闭流
bufferedOutputStream.flush();
} catch (IOException e) {
log.info(e.getMessage());
e.printStackTrace();
}
ByteArrayInputStream
- ByteArrayInputStream的实现主要是基于内部的字节数组,在创建ByteArrayInputStream对象的时候将字节数组传入构造方法,该字节数组九城了输入流的数据源,再度取得时候在内部使用指针来进行追踪读取的位置,没读取一次,指针向前移动一次
- 处理的机制;读取字节->读取字节数组
- 优缺点
- 适用于在内存中进行操作,不需要外部文件跟网络交互 他由于数据源在内存当中 读取的速度会很快
- 内存消耗的比较大,不太适合动态追加数据,因为数据源是提前存在的字节数组
byte[] data = {72, 101, 108, 108, 111}; // ASCII codes for 'H', 'e', 'l', 'l', 'o'
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data)) {
int byteRead;
while ((byteRead = byteArrayInputStream.read()) != -1) {
// 处理读取到的字节
System.out.print((char) byteRead);
}
} catch (IOException e) {
log.info(e.getMessage())
e.printStackTrace();
}
OutputStreamWriter
- OutputStreamWriter是字节流到字符流中间的桥梁,用于将字节流转为字符流,它继承的是writer,构造方法中可以指定字符编码,用于将字节按照指定的编码格式转为字符
- 在创建OutputStreamWriter的时候需要指定底层的字节输出流(OutputStream)和字符编码,OutputStreamWriter的实现机制就是将写入OutputStreamWriter的字符按照指定的字符编码进行转换,然后在通过字节输入流将东西写入到文件或者网络等
- 优缺点:
- 提供了特别方便的字符编码的转换,适合处理文本数据的场景
- 性能的开销会比较大
try (OutputStream outputStream = Files.newOutputStream(Paths.get("example.txt"));
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
// 写入字符数据
String data = "Hello, how are you?!";
outputStreamWriter.write(data);
// 刷新并关闭流
outputStreamWriter.flush();
} catch (IOException e) {
log.info(e.getMessage())
e.printStackTrace();
}
FileWriter
- 它的实现就是将字符按照默认的编码转成字节 然后通过FineOutputStream写到文件中
- 在创建FileWriter的时候可以指定文件名或者文件对象,也可以选择是否在文件末尾追加
- 优缺点:
- 操作简单,不需要手动的转换成字节,特别适用于文本数据
- 默认的字符编码可能会导致跨平台环境下的问题,性能的开销比较大
try (FileWriter fileWriter = new FileWriter("file.txt")) {
// 写入字符数据
String data = "Hello, how are you?!";
fileWriter.write(data);
// 刷新并关闭流
fileWriter.flush();
} catch (IOException e) {
log.info(e.getMessage());
e.printStackTrace();
}
BufferedWriter
- BufferedWriter在写入的时候会将数据先存放在内部缓存区,然后手动调用flush方法或者是缓冲区满的时候,将缓冲区的数据写到字符输出力汇总
- 优缺点:
- 缓冲机制有着显著的提高写入的性能,减少了实际的底层写入的次数,特别适用于大量的数据
- 因为缓冲机制写入有可能会造成数据的不实时性
try (FileWriter fileWriter = new FileWriter("file.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
// 写入字符数据
String data = "Hello, how are you?!";
bufferedWriter.write(data);
// 刷新并关闭流
bufferedWriter.flush();
} catch (IOException e) {
log.info(e.getMessage());
e.printStackTrace();
}
StringWriter
- StringWriter的实现机制就是在内部维护了一个StirngBuffer对象 在调用write方法时候写入,实际就是将字符数据追加到内部的StringBuffer中
- 优缺点
- 方便的构建字符串,适合用于文本操作
- 不太适合处理大量的数据
try (StringWriter stringWriter = new StringWriter()) {
// 写入字符数据
stringWriter.write("Hello, how are you ?!");
// 获取构建的字符串
String result = stringWriter.toString();
System.out.println(result);
} catch (IOException e) {
log.info(e.getMessage());
e.printStackTrace();
}
总结
提示:java进阶之路学习笔记