目录
一、IO
1、IO的概念
在程序设计过程中,输入输出(Input/Output)尤为重要。程序在运行过程中需要获取外部数据进行操作。其中外部数据可能保存在文件、数据库、网络、其他程序中等等。所以我们需要运用IO来操作外部数据。
输入(Input):程序从外部系统获取数据的过程
输出(Output):程序输出数据到外部数据的过程
数据源(Data Source):提供数据的一端
2、流的概念
流是一个抽象的概念,它就是一连串的数据。
输入流:通过流将数据源中的数据输送到程序中去
输出流:通过流将程序中的数据输送到数据源中
二、四大IO抽象类
1、java流的分类
1、按数据流的方向:
输入流:数据流从数据源到程序
输出流 :数据流从程序到目的地
2、按处理数据单元:
字节流:以字节为单位获取数据
字符流:以字符为度单位获取数据
3、按处理对象不同:
节点流:可以直接从数据源或目的地址读写数据
处理流:不直接连接到数据源或目的地,通过对其他流的处理提高程序性能,也叫包装流
2、编码
编码就是把字符转换为字节,而解码是把字节重新组合成字符。
如果编码和解码过程使用不同的编码方式那么就出现了乱码。
GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节;
UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节;
UTF-16be 编码中,中文字符和英文字符都占 2 个字节。
三、IO类
1、File类
public class File extends Object implements Serializable, Comparable<File>
File类的常用方法:
boolean delete()
删除由此抽象路径名表示的文件或目录。
boolean exists()
测试此抽象路径名表示的文件或目录是否存在。
String[] list()
返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。
File[] listFiles()
返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。
boolean isFile()
测试此抽象路径名表示的文件是否为普通文件。
boolean isDirectory()
测试此抽象路径名表示的文件是否为目录。
测试:
public class FileDemo {
public static void main(String[] args) throws IOException {
File file = new File("C:Test.txt");
// 判断文件是否存在
if (!file.exists()) {
// 创建文件
file.createNewFile();
}
// 刪除文件
file.delete();
}
}
2、字节输入输出流
FileInputStream
和FileOutputStream
2.1 字节流文件拷贝的方式
// 方式一
public static void main(String[] args) throws IOException {
String srcPath = "c:/test1.txt";
String DestPath = "d:/test1.txt";
int fileLen = 0;
FileInputStream fileInputStream = new FileInputStream(srcPath);
FileOutputStream fileOutputStream = new FileOutputStream(DestPath);
byte[] buf = new byte[1024];
// fileInputStream.read()读取一个字节的数据 范围为0-255
// fileInputStream.read(buf)读取最多buf.length个字节的数据
while((fileLen = fileInputStream.read(buf)) != -1){
// 将filelen字节从0偏移量写入此文件输出流
fileOutputStream.write(buf,0,fileLen);
}
fileInputStream.close();
fileOutputStream.close();
}
// 方式2
public static void main(String[] args) throws IOException {
String srcPath = "c:/test1.txt";
String DestPath = "d:/test1.txt";
int fileLen = 0;
FileInputStream fileInputStream = new FileInputStream(srcPath);
FileOutputStream fileOutputStream = new FileOutputStream(DestPath);
// fileInputStream.available() 从此输入流中可以读取(或跳过)的剩余字节数的估计值
byte[] buf = new byte[fileInputStream.available()];
fileInputStream.read(buf);
fileOutputStream.write(buf);
fileInputStream.close();
fileOutputStream.close();
}
比较上述两个代码,我们发现方式2读写的速度更快,但是在实际应用中,如果我们要操作的文件比较大时,建议选择方式1,因为方式2虽然速度快,但是空间消耗非常大。
提高文件操作效率
前面我们可以通过byte[]
数组达到数据缓冲的作用,Java有一种缓冲流,缓冲流本身不具有IO流的读写功能,它在别的流的基础上加上缓冲功能提高效率。
BufferedInputStream
和BuffererdOutputStream
2.2 字节缓存流实现文件的拷贝
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream("c:/Test.txt");
bis = new BufferedInputStream(fis);
fos = new FileOutputStream("c:/Test1.txt");
bos = new BufferedOutputStream(fos);
// 缓冲流中byte数组长度默认为8192
// private static int DEFAULT_BUFFER_SIZE = 8192;
int temp = 0;
while((temp = bis.read()) != -1) {
bos.write(temp);
}
bos.flush();
}catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(bos != null) {
bos.close();
}
if(fos != null) {
fos.close();
}
if(bis != null) {
bis.close();
}
if(fis != null) {
fis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、文本字符输入输出流
FileReader
和FileWriter
public static void FileReaderTest(String[] args) throws IOException {
String filePath = "c:/test.txt";
FileReader fileReade = new FileReader(filePath);;
int fileDate = 0;
while((fileDate = fileReade.read()) != -1) {
System.out.print((char) fileDate);
}
fileReade.close();
}
public static void FileWriterTest(String[] args) throws IOException {
String filePath = "c:/note.txt";
FileWriter fileWriter = new FileWriter(filePath);
// 写入一个字符
fileWriter.write("h");
// 写入一个字符数组
char[] buf = {'1','2','3','4'};
fileWriter.write(buf);
// 写入字符串
String str = "小姜~超幸运,爱学习";
fileWriter.write(str);
// 截取字符串内容并写入
fileWriter.write(str,0,6);
fileWriter.close();
}
FileWriter
提供的构造方法有FileWriter(File file, boolean append)
,这个构造方法有两个参数,第一个表示文件的路径,第二个表示是否可以追加,如果为true,则表示可以追加,反之为覆盖。
3.1 字符流实现文件的拷贝
public static void main(String[] args) throws IOException {
String filePath1 = "c:/test1.txt";
String filePath2 = "c:/test2.txt";
FileReader fr = new FileReader(filePath1);
FileWriter fw = new FileWriter(filePath2);
int fileDate = 0;
char[] buf = new char[1024];
while((fileDate = fr.read()) != -1) {
fw.write(buf,0,fileDate);
}
fw.close();
fr.close();
}
提高文件操作效率
在字符流中同样有字符缓冲流对字符流增加缓存机制,大大提高了读写文件的效率。
BufferedReader
和BufferedWriter
public static void BufferedReaderTest(String[] args) throws IOException {
String filePath = "C:/test.txt";
BufferedReader br = new BufferedReader(new FileReader(filePath));
String str = "";
// br.readLine() 读取的是一行的内容 返回值为null结束
while((str = br.readLine()) != null) {
System.out.println(str);
}
br.close();
}
public static void BufferedWriterTest(String[] args) throws IOException {
String filePath = "c:/test.txt";
BufferedWriter bw = new BufferedWriter(new FileWriter(filePath));
bw.write("hello,小姜");
// 回车换行
bw.newLine();
bw.write("hello,小姜\n");
bw.close();
}
3.2 字符缓存流实现文件的拷贝
public static void main(String[] args) throws IOException {
String filePath1 = "c:/test1.txt";
String filePath2 = "c:/test2.txt";
BufferedReader br = new BufferedReader(new FileReader(filePath1));
BufferedWriter bw = new BufferedWriter(new FileWriter(filePath2));
String temp = "";
while((temp = br.readLine()) != null) {
bw.write(temp);
bw.newLine();
}
bw.flush();
bw.close();
br.close();
}
4、转换流
InputStreamReader
和OutputStreamWriter
将字节流转化成字符流
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 使用转换流输出
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
// 使用字符输出流输出
PrintWriter pw = new PrintWriter("d:/test.txt");
// 终端读取键盘输入文本内容
String input = br.readLine();
// 终端打印文本内容
bw.write(input);
// 写入到文件中
pw.println(input);
bw.close();
pw.close();
br.close();
}
5、字节数组输入输出流
ByteArrayInputStream
和ByteArrayOutputStream
public static void ByteArrayInputStreamTest(String[] args) {
byte[] arr = "ancdefg".getBytes();
ByteArrayInputStream bis = new ByteArrayInputStream(arr);
StringBuilder sb = new StringBuilder();
int temp = 0;
while((temp = bis.read()) != -1) {
sb.append((char)temp);
}
System.out.println(sb);
}
public static void ByteArrayOutputStreamTest(String[] args) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
StringBuilder sb = new StringBuilder();
bos.write('a');
bos.write('b');
bos.write('c');
byte[] arr = bos.toByteArray();
for (int i = 0; i < arr.length; i++) {
sb.append((char)arr[i]);
}
System.out.println(sb);
}
6、对象流
序列化
序列化就是将一个对象转换成字节序列,方便存储和传输。
序列化:ObjectOutputStream.writeObject()
反序列化:ObjectInputStream.readObject()
序列化的类需要实现 Serializable 接口,它是一个空接口,但是如果不去实现它的话而进行序列化,会抛出异常。
public class SerializationTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String filePath = "d:/test.txt";
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(filePath));
ObjectInputStream oi = new ObjectInputStream(new FileInputStream(filePath));
oo.writeObject(new JiaQi("小姜", 21));
JiaQi j = (JiaQi) oi.readObject();
System.out.println(j.toString());
oo.close();
oi.close();
}
}
class JiaQi implements Serializable {
private String name;
private int age;
public JiaQi(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "JiaQi{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}