第1集 Java核心字符编码和字符-字节流介绍
简介:Java核心字符编码和字符-字节流介绍
-
什么是编码
-
什么是java的IO流
- Java中的I/O(输入/输出)流是用于处理数据输入和输出的抽象类。
- Java I/O流主要分为两大类:字节流(Byte Streams)和字符流(Character Streams)。
- 字节流:用于处理二进制数据,包括InputStream和OutputStream两个主要类及其子类。
- 字符流:用于处理文本数据,包括Reader和Writer两个主要类及其子类。
-
字节和字符流区别
- 处理的数据类型
- 字节流
- 处理的是字节数据,即8位二进制数据,在计算机中,所有的文件都能以二进制(字节)形式存在。
- Java的I/O中针对字节传输操作提供了一系列流,统称为字节流。
- 这些流包括两个抽象基类InputStream和OutputStream,分别处理字节流的输入和输出
- 字符流
- 处理的是字符数据,即Unicode字符,通常是16位二进制数据。
- 字符流是16位unicode字符流,主要用于处理字符和文本文件。
- 由于Java中字符是采用Unicode标准,因此字符流在处理文本数据时具有更高的效率和准确性。
- 编码问题
- 字节流
- 因为直接操作的是字节,没有编码问题,字节流可以处理任意类型的数据,包括文本、图片、音频等。
- 当使用字节流处理文本文件时,需要自行处理编码问题,否则可能会出现乱码
- 字符流
- Java使用Unicode编码来表示字符,而外部数据源可能使用不同的编码方式。
- 字符流在读取或写入文本文件时,会自动进行字符编码的转换,使用字符流处理文本文件时通常不需要担心编码问题。
- 使用场景
- 字节流:
- 字节流以字节(8bit)为单位,适合处理图片、视频、音频等二进制文件,以及网络传输等场景。
- 由于字节流直接操作字节数据,因此具有更高的灵活性和效率
- 字符流:
- 字符流以字符为单位,根据码表映射字符,一次可能读多个字节,适合处理文本文件、文本数据等场景。
- 字符流在处理文本数据时具有更高的效率和准确性,因为字符流会自动处理字符编码的转换
-
IO流相关类体系概览

第2集 Java输入流InputStream案例实战
简介:讲解InputStream相关介绍及其子类
-
InputStream
- 是输入字节流的父类,它是一个抽象类(一般用他的子类)
- 在Java中,
InputStream
是所有字节输入流的超类。
- 它定义了字节流输入的基本操作,如读取字节、跳过字节和标记/重置流等。
- 通过
InputStream
,我们可以从文件、网络连接或其他数据源中读取字节数据。
-
常见方法
-
int read()
- 从输入流中读取单个字节,返回0到255范围内的int字节值, 字节数据可直接转换为int类型
- 如果已经到达流末尾而没有可用的字节,则返回-1
-
int read(byte[] b)
:
- 从输入流中读取最多
b.length
个字节的数据到字节数组b
中,并返回实际读取的字节数。
- 如果因为已经到达流末尾而没有更多的数据,则返回-1。

-
int read(byte[] b, int off, int len)
:
- 从输入流中读取最多
len
个字节的数据到字节数组b
中,从off
指定的偏移量开始存储,并返回实际读取的字节数。
- 如果因为已经到达流末尾而没有更多的数据,则返回-1。
-
long skip(long n)
:
- 跳过输入流中的
n
个字节。如果实际跳过的字节数小于n
,则可能是因为已经到达流的末尾。
- 此方法返回实际跳过的字节数。
-
int available()
:返回可以从此输入流中读取的字节数的估计值。
-
void close()
:关闭此输入流并释放与该流关联的系统资源。
-
常见子类
-
FileInputStream
- 抽象类InputStream用来具体实现类的创建对象, 文件字节输入流, 对文件数据以字节的形式进行读取操作
//常用构造函数,传入文件所在地址
public FileInputStream(String name) throws FileNotFoundException
//常用构造函数,传入文件对象
public FileInputStream(File file) throws FileNotFoundException
-
ByteArrayInputStream 字节数组输入流
-
ObjectInputStream 对象输入流
-
....还有很多
-
案例实战
public class InputStreamDemo {
public static void main(String[] args) {
String dir = "/Users/xdclass/Desktop/coding/xdclass-account/src/chapter11";
String name = "a.txt";
File file = new File(dir, name);
try (InputStream inputStream = new FileInputStream(file)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
// 处理读取到的数据(例如打印到控制台)
System.out.println(new String(buffer, 0, bytesRead));
//中文乱码问题,换成GBK 或者 UTF-8
//System.out.println(new String(buffer,"UTF-8"));
//System.out.println(new String(buffer,0, bytesRead,"UTF-8"));
//System.out.println(new String(buffer, 0, bytesRead));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
注意
- 在上面的示例中,使用了try-with-resources语句来自动关闭
InputStream
。
- 这是JDK 7及更高版本引入的一个新特性,用于确保在不再需要资源时自动关闭它们。
-
编码小知识(节省空间)
-
操作的中文内容多则推荐GBK:
- GBK中英文也是两个字节,用GBK节省了空间,
- UTF-8 编码的中文使用了三个字节
-
如果是英文内容多则推荐UFT-8:
- 因为UFT-8里面英文只占一个字节
- UTF-8编码的中文使用了三个字节
-
IDEA编码格式配置

第3集 Java输出流 OutputStream案例实战
简介:讲解OutputStream相关介绍及其子类
-
OutputStream
- 是输出字节流的父类,它是一个抽象类,在Java中,
OutputStream
是所有字节输出流的超类。
- 它定义了字节流输出的基本操作,如写入字节、刷新输出流和关闭输出流等。
- 通过
OutputStream
,可以将数据写入文件、网络连接或其他数据接收端。
-
OutputStream的主要方法
void write(int b)
:将指定的字节写入此输出流。
void write(byte[] b)
:将b.length
个字节从指定的字节数组写入此输出流。

void write(byte[] b, int off, int len)
:从指定的字节数组写入len
个字节,从偏移量off
开始。
void flush()
- 刷新此输出流并强制写出任何缓冲的输出字节,
- 进行输出时,为了提高效率,这些类通常会实现缓存机制。
- 当调用
write()
方法写入数据时,数据可能并不会立即被发送到目标位置,而是先被存储在内部缓冲区中。
- 当缓冲区满或我们显式地调用
flush()
方法时
void close()
:关闭此输出流并释放与此流相关联的任何系统资源
-
OutputStream的子类
FileOutputStream
,抽象类用来具体实现类的创建对象, 文件字节输出流, 对文件数据以字节的形式进行输出的操作
//传入输出的文件地址
public FileOutputStream(String name)
//传入目标输出的文件对象
public FileOutputStream(File file)
//传入目标输出的文件对象, 是否可以追加内容
public FileOutputStream(File file, boolean append)
ByteArrayOutputStream
:在内存中创建一个缓冲区,所有写入流的数据都会置入这个缓冲区。
- ....还有很多
-
案例实战
public class OutputStreamExample {
public static void main(String[] args) {
String dir = "/Users/xdclass/Desktop/coding/xdclass-account/src/chapter11";
String name = "b.txt";
try (OutputStream outputStream = new FileOutputStream(file)) {
String data = "Hello, World!";
outputStream.write(data.getBytes());
outputStream.flush(); // 确保所有数据都写入文件
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
注意:在Java中,通常会在以下情况下调用flush()
方法:
- 在完成所有写入操作并希望确保所有数据都被发送到目标位置时。
- 在需要在写入过程中立即看到数据的效果时(例如,在网络编程中)。
- 在关闭输出流之前,以确保所有缓冲的数据都被发送出去。
第4集 Java IO包之缓冲Buffer输入输出流介绍
简介: Java IO包之缓冲Buffer输入输出流介绍
-
什么是缓冲Buffer
- 它是内存空间的一部分,在内存空间中预留了一定的存储空间
- 这些存储空间用来缓冲输入或输出的数据,这部分空间就叫做缓冲区,缓冲区是具有一定大小的
- 当使用缓冲流时,数据首先被读写到缓存区中,然后再从缓存区传输到目标位置(如文件、网络等)。
- 这种方式减少了直接对目标位置的读写操作,因此提高了性能。
-
为啥要用缓冲
- 缓冲,缓和冲击,例如操作磁盘比内存慢的很多,所以不用缓冲区效率很低,数据传输速度和数据处理的速度存在不平衡
- 比如
- 每秒要读写100次硬盘,对系统冲击很大,浪费了大量时间在忙着处理开始写和结束写这两个事件
- 所以用内存的buffer暂存起来,变成每10秒写一次硬盘,数据可以直接送往缓冲区
- 高速设备不用再等待低速设备,对系统的冲击就很小,写入效率高了
-
Java中的缓冲输入流与输出流(提供了四种Buffer流)
- BufferedInputStream:缓存输入流,封装了InputStream,提供了缓存区来暂存输入数据。
- BufferedOutputStream:缓存输出流,封装了OutputStream,提供了缓存区来暂存输出数据。
- BufferedReader:缓存字符输入流,封装了Reader,提供了缓存区来暂存字符输入数据。
- BufferedWriter:缓存字符输出流,封装了Writer,提供了缓存区来暂存字符输出数据。
- 采用的装饰器设计模式(锦上添花)
-
主要特点:由于使用了缓存区,因此减少了直接对目标位置的读写操作,从而提高了性能。
-
BufferedInputStream 缓冲字节输入流
-
通过预先读入一整段原始输入流数据至缓冲区中,外界对BufferedInputStream的读取操作实际上是在缓冲区上进行,
-
如果读取的数据超过了缓冲区的范围,BufferedInputStream负责重新从原始输入流中载入下一截数据,填充缓冲区
-
然后外界继续通过缓冲区进行数据读取,避免了大量的磁盘IO,原始的InputStream类实现的read是即时读取的
-
因为每一次读取都会是一次磁盘IO操作(哪怕只读取了1个字节的数据),如果数据量巨大,这样的磁盘消耗非常可怕。
-
读取可以读取缓冲区中的内容,当读取超过缓冲区的内容后再进行一次磁盘IO
-
载入一段数据填充缓冲,下一次读取一般情况就直接可以从缓冲区读取,减少了磁盘IO。
-
默认缓冲区大小是8k, int DEFAULT_BUFFER_SIZE = 8192;
-
构造函数
//对输入流进行包装,里面默认的缓冲区是8k
public BufferedInputStream(InputStream in);
//对输入流进行包装,指定创建具有指定缓冲区大小的
public BufferedInputStream(InputStream in,int size);
-
常用方法
/从输入流中读取一个字节
public int read();
//从字节输入流中,给定偏移量offset处开始, 将len字节读取到指定的byte数组中。
public int read(byte[] buf,int off,int len);
//关闭释放资源,关闭的时候这个流即可,InputStream会在里面被关闭
void close();
-
BufferedOutputStream 缓冲字节输出流
- 内部使用一个缓冲区来暂存待写入的数据。
- 当缓冲区满时,或者调用
flush()
方法时,缓冲区中的数据会被一次性写入到底层输出流中。
- 这种机制提高了数据写入的效率,减少了系统I/O操作的次数。
- 构造函数
//对输出流进行包装,里面默认的缓冲区是8k
public BufferedOutputStream(OutputStream out);
//对输出流进行包装,指定创建具有指定缓冲区大小的
public BufferedOutputStream(OutputStream out,int size);
//向输出流中输出一个字节
public void write(int b);
//将指定 byte 数组中从偏移量 off 开始的 len 个字节写入缓冲的输出流。
public void write(byte[] buf,int off,int len);
//刷新此缓冲的输出流,强制使所有缓冲的输出字节被写出到底层输出流中。
public void flush();
//关闭释放资源,关闭的时候这个流即可,OutputStream会在里面被关闭, JDK7新特性try(在这里声明的会自动关闭){}
void close();
第5集 新版缓冲Buffer输入输出流综合案例实战
简介: 新版缓冲Buffer输入输出流综合案例实战
-
新版try-with-resource语法
- 在Java中,从JDK 7开始,可以使用try-with-resources语句
- 来自动管理实现了
AutoCloseable
或Closeable
接口的资源如文件流、缓冲流等。
- 这种语法可以确保资源在try代码块执行完毕后被正确关闭,即使try块中的代码抛出了异常。
-
缓冲流输入案例实战
- 创建了一个
FileInputStream
并将其包装在BufferedInputStream
中。
- 通过
bis.read(buffer)
方法,可以从文件中读取数据到缓冲区中,并在读取过程中处理这些数据。
- 在try代码块结束后,
BufferedInputStream
和FileInputStream
都会被自动关闭
import java.io.*;
public class BufferedInputStreamExample {
public static void main(String[] args) {
String inputFilePath = "input.txt"; // 假设这个文件存在并包含一些数据
try (FileInputStream fis = new FileInputStream(inputFilePath);
BufferedInputStream bis = new BufferedInputStream(fis)) {
byte[] buffer = new byte[1024];
int bytesRead;
// 读取数据
while ((bytesRead = bis.read(buffer)) != -1) {
// 处理读取到的数据(这里只是简单地打印出来)
System.out.print(new String(buffer, 0, bytesRead));
}
// 注意:由于使用了try-with-resources,close()方法在这里是自动调用的
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
缓冲流输出案例实战
- 在这个例子中,创建了一个
FileOutputStream
并将其包装在BufferedOutputStream
中。
- 在try代码块结束后,
BufferedOutputStream
和FileOutputStream
都会被自动关闭,因为它们都实现了AutoCloseable
接口。
import java.io.*;
public class BufferedOutputStreamExample {
public static void main(String[] args) {
String outputFilePath = "output.txt";
try (FileOutputStream fos = new FileOutputStream(outputFilePath);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
// 写入数据到缓冲区
String data = "Hello, World!";
bos.write(data.getBytes());
// 注意:由于使用了try-with-resources,flush()和close()方法在这里是自动调用的
System.out.println("数据已成功写入文件。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
拓展旧版语法,流的关闭顺序: 后开先关, 如果A依赖B,先关闭B
public class BufferedInputStreamExample {
public static void main(String[] args) {
try {
// 创建一个文件输入流
FileInputStream fis = new FileInputStream("example.txt");
// 创建一个缓冲输入流,并封装文件输入流
BufferedInputStream bis = new BufferedInputStream(fis);
// 定义一个字节数组用于存储读取的数据
byte[] buffer = new byte[1024];
int bytesRead;
// 循环读取数据直到文件末尾
while ((bytesRead = bis.read(buffer)) != -1) {
// 处理读取到的数据(这里只是简单地打印出来)
System.out.println(new String(buffer, 0, bytesRead));
}
// 关闭缓冲输入流和文件输入流
bis.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class BufferedOutputStreamExample {
public static void main(String[] args) {
try {
// 创建一个文件输出流
FileOutputStream fos = new FileOutputStream("output.txt");
// 创建一个带缓冲区的输出流,并封装文件输出流
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 写入数据到缓冲区
String data = "Hello, World!";
bos.write(data.getBytes());
// 刷新缓冲区,确保数据被写入文件
bos.flush();
// 关闭输出流和底层流
bos.close();
fos.close();
System.out.println("数据已成功写入文件。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
第6集 课程作业之Java实现文件的拷贝案例实战《上》
简介: 课程作业之Java实现文件的拷贝案例实战
-
需求
- 编写一个Java程序,实现将一个文件从源路径复制到目标路径的功能。
- 在这个过程中,你需要使用
BufferedInputStream
和BufferedOutputStream
来提高文件传输的效率。
-
作业思路参考
- 定义一个
copyFile
方法,该方法接收两个参数:源文件的路径和目标文件的路径
- 在
copyFile
方法中,使用BufferedInputStream
和BufferedOutputStream
来读取源文件内容并写入到目标文件中。
- 确保在拷贝文件的过程中,源文件和目标文件都可以是任意大小的文件,并且拷贝过程应该能够处理大文件。
- 在拷贝完成后,输出一条消息到控制台,表示文件拷贝成功。
- 如果在拷贝过程中发生任何异常(如源文件不存在、目标文件无法创建等),请捕获异常并输出一条错误消息到控制台。
- 最后,编写一个
main
方法来测试你的copyFile
方法。
-
参考骨架案例
import java.io.*;
public class FileCopier {
public static void copyFile(String sourceFilePath, String targetFilePath) {
// 在这里实现文件拷贝逻辑
}
public static void main(String[] args) {
// 示例源文件和目标文件路径
String sourceFilePath = "path/to/source/file.txt";
String targetFilePath = "path/to/target/file.txt";
// 调用copyFile方法
try {
copyFile(sourceFilePath, targetFilePath);
System.out.println("文件拷贝成功!");
} catch (Exception e) {
System.err.println("文件拷贝失败:" + e.getMessage());
}
}
}
-
知识点进阶:Files和Paths类
-
java.nio.file
包是 Java 7 引入的一个新的文件系统 API,提供了更加灵活的文件 I/O 操作。
-
这个包中的 Files
和 Paths
类是文件操作中非常常用的两个工具类
-
Files
类提供了一系列静态方法,用于在文件系统中执行各种操作,如读取、写入、复制、移动、删除文件等
Files.readAllBytes(Path path)
: 读取指定路径的文件到字节数组中。
Files.delete(Path path)
: 删除文件或目录。
Files.exists(Path path, LinkOption... options)
: 检查文件或目录是否存在。
Files.createDirectories(Path dir, FileAttribute<?>... attrs)
: 创建目录,包括所有不存在的父目录。
-
Paths
是一个工具类,用于创建和操作 Path
对象,是 java.nio.file
包中的一个重要类,表示文件系统中的一个路径
Paths
类中常用的方法是 Paths.get(URI uri)
它们用于创建 Path
对象;Path
对象提供了很多方法来操作和查询路径
Path path = Paths.get("/home/user/file.txt");
-
Path.getFileName()
: 获取路径中的文件名。
-
Path.getParent()
: 获取路径的父目录。
-
Path.toFile()
: 将路径转换为 File
对象(注意,File
类是 java.io
包中的类)。
第7集 课程作业之Java实现文件的拷贝案例实战《下》
简介: 课程作业之Java实现文件的拷贝案例实战
-
具体实现
package chapter11;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileCopier {
public static void copyFile(String sourceFilePath, String targetFilePath) throws IOException {
// 检查目标文件路径中的目录是否存在
Path targetPath = Paths.get(targetFilePath).getParent();
if (targetPath != null && !Files.exists(targetPath)) {
// 如果目录不存在,则创建它
Files.createDirectories(targetPath);
}
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFilePath));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFilePath))) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
// 注意:由于使用了try-with-resources,流在这里会被自动关闭
}
}
public static void main(String[] args) {
// 示例源文件和目标文件路径
String sourceFilePath = "/Users/xdclass/Desktop/coding/xdclass-account/src/chapter11/a.txt";
String targetFilePath = "/Users/xdclass/Desktop/coding/xdclass-account/src/chapter11/a/target/file.txt";
// 调用copyFile方法
try {
copyFile(sourceFilePath, targetFilePath);
System.out.println("文件拷贝成功!");
} catch (IOException e) {
System.err.println("文件拷贝失败:" + e.getMessage());
}
}
}
- 思路流程
- 使用
FileInputStream
和FileOutputStream
分别创建源文件和目标文件的输入/输出流。
- 将
FileInputStream
包装在BufferedInputStream
中,以便使用缓冲来提高读取效率。
- 将
FileOutputStream
包装在BufferedOutputStream
中,以便使用缓冲来提高写入效率。
- 使用循环和
read
、write
方法来从源文件读取数据并写入目标文件,直到没有更多数据可读为止。
- 在
finally
块中(或使用try-with-resources)确保关闭所有打开的流