一、概念
io流用来读写文件中的数据 i:input o:output
二、分类
1、按流的方法分为:输入流、输出流
2、按操作文件的类型分为:字节流、字符流
其中字节流能处理所有类型的文件 字符流只能处理纯文本文件
纯文本文件可以通过windows自带的记事本能打开且内容可以看得懂 包括txt、md文件
总结:
三、io流详解
1、字节流之FileOutputStream
(1)、概念
操作本地文件的字节输出流 可以将程序中的数据写到本地文件
(2)、步骤
1、创建对象(让程序和文件之间建立一个通道)
2、写数据
3、释放资源(断开程序和文件之间建立一个通道)
防止java程序占用资源 使得在其它程序中可以打开
(3)、细节
细节1:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class test1 {
public static void main(String[] args) throws IOException {
// 创建对象
// 也可以是字符串表示的路径
FileOutputStream fos1=new FileOutputStream("D:\\测试安全\\c.txt");
// 写数据
fos1.write(97);
// 释放资源
fos1.close();
// 创建对象
// 参数可以是File对象表示的路径
File f=new File("a.txt");
FileOutputStream fos2=new FileOutputStream(f);
// 写数据
fos2.write(98);
// 释放资源
fos2.close();
}
}
细节2:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class test2 {
public static void main(String[] args) throws IOException {
// 创建对象
// 也可以是字符串表示的路径
// 如果文件路径不存在 就会创建文件 前提是父级路径存在
FileOutputStream fos1=new FileOutputStream("D:\\测试安全\\d.txt");
// 写数据
fos1.write(99);
// 释放资源
fos1.close();
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class test2 {
public static void main(String[] args) throws IOException {
// 创建对象
// 也可以是字符串表示的路径
// 如果文件路径不存在 就会创建文件 前提是父级路径存在
// 父级路径不存在 就会报错
FileOutputStream fos1=new FileOutputStream("D:\\测试安全\\f\\e.txt");
// 写数据
fos1.write(99);
// 释放资源
fos1.close();
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class test2 {
public static void main(String[] args) throws IOException {
// 创建对象
// 也可以是字符串表示的路径
// 如果文件路径不存在 就会创建文件 前提是父级路径存在
// 父级路径不存在 就会报错
FileOutputStream fos1=new FileOutputStream("D:\\测试安全\\d.txt");
// 写数据
// 覆盖写
fos1.write(101);
fos1.write(102);
fos1.write(103);
// 释放资源
fos1.close();
}
}
(4)、写数据的三种方式
FileOutputStream对象.write(int b) 一次写一个字节数据
FileOutputStream对象.write(byte [] b) 一次写一个字节数组数据
FileOutputStream对象.write(byte [] b,int off,int len) 一次写一个字节数组部分数据
off表示起始索引 len表示写入的总个数
方式一:
方式二:
方式三:
(5)、换行写、续写
换行写:添加\r\n
import java.io.FileOutputStream;
import java.io.IOException;
public class test3 {
public static void main(String[] args) throws IOException {
// 创建对象
FileOutputStream fos1=new FileOutputStream("a.txt");
// 写数据
/*
当输入的内容很多时 我们可以先定义字符串
通过字符串.getBytes()的方法将字符串的每个字符转化为其Ascii码值
形成数组
*/
String str1="你好 java helloworld";
byte [] byte1=str1.getBytes();
fos1.write(byte1);
// 换行
String str2="\r\n";
byte[] byte2 = str2.getBytes();
fos1.write(byte2);
String str3="java是世界上最好的语言";
byte [] byte3=str3.getBytes();
fos1.write(byte3);
// 释放资源
fos1.close();
}
}
续写:在创建FileOutputStream对象是 添加参数true
import java.io.FileOutputStream;
import java.io.IOException;
public class test3 {
public static void main(String[] args) throws IOException {
// 创建对象
FileOutputStream fos1=new FileOutputStream("a.txt",true);
// 写数据
/*
当输入的内容很多时 我们可以先定义字符串
通过字符串.getBytes()的方法将字符串的每个字符转化为其Ascii码值
形成数组
*/
String str1="你好 java helloworld";
byte [] byte1=str1.getBytes();
fos1.write(byte1);
// 换行
String str2="\r\n";
byte[] byte2 = str2.getBytes();
fos1.write(byte2);
String str3="java是世界上最好的语言";
byte [] byte3=str3.getBytes();
fos1.write(byte3);
// 释放资源
fos1.close();
}
}
(6)、小结
2、字节流之FileInputStream
(1)、概念
操作本地文件的字节输入流 可以将本地文件的数据输入到程序中
(2)、步骤
1、创建对象(让程序和文件之间建立一个通道)
2、读数据
3、释放资源(断开程序和文件之间建立一个通道)
防止java程序占用资源 使得在其它程序中可以打开
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class test4 {
/*
1、创建对象(让程序和文件之间建立一个通道)
2、读数据
3、释放资源(断开程序和文件之间建立一个通道)
防止java程序占用资源 使得在其它程序中可以打开
*/
public static void main(String[] args) throws IOException {
// 1.创建对象
FileInputStream fis=new FileInputStream("a.txt");
// 2.读数据
// 每次读取一个数据 依次读取 返回值是字符对应的ASCII码值 全部读取完 返回-1
int read = fis.read();
while (read!=-1) {
System.out.print((char) read);
read = fis.read();
}
// 3.释放资源
fis.close();
// 输出:
// java helloworld
}
}
(3)、细节
细节1:
(4)、循环读取
import java.io.FileInputStream;
import java.io.IOException;
public class test5 {
public static void main(String[] args) throws IOException {
// 1.创建对象
// 该文件不存在
FileInputStream fis=new FileInputStream("b.txt");
// 2.读数据
// 依次读取读取一个数据 指针后移 返回值是字符对应的ASCII码值 如果全部读取完 返回-1
// ascii码表中不存在acsii码值为-1的字符
int read;
while ((read=fis.read())!=-1) {
System.out.print((char) read);
}
// 3.释放资源
fis.close();
}
}
(5)、读数据的两种方式
一次读取一个字节在之前我们已经学习了 现在我们重点学习一次读取多个字节
步骤:
1、创建对象(让程序和文件之间建立一个通道)
2、创建动态数组 数组的长度决定了每次最多读取的个数
3、通过对象.read(数组);存放读到的数据 并通过int len存放返回值
4、创建字符串 String str=new String(bytes,0,len);
5、输出字符串 即可输出读到的数据
防止java程序占用资源 使得在其它程序中可以打开
import java.io.FileInputStream;
import java.io.IOException;
public class test7 {
public static void main(String[] args) throws IOException {
// 1.创建对象
// 该文件不存在
FileInputStream fis=new FileInputStream("d.txt");
// 2.读数据
// 定义一个长度为4的数组 数组的长度决定了每次最多读取的个数
// 每次读取的数据都会存放在数组中 数组是重复利用的 每次存放的数据都会覆盖原来的数据
byte [] bytes=new byte[4];
// fis.read(bytes)该方法的返回值是实际读取的数据个数
int len1=fis.read(bytes);
System.out.println("第一次读取的数据个数"+len1);
// 创建字符数组部分内容的字符串 因为字符数组有的数据没有被覆盖 是原来的内容 属于无效数据
String str1=new String(bytes,0,len1);
System.out.println(str1);
int len2=fis.read(bytes);
System.out.println("第二次读取的数据个数"+len2);
String str2=new String(bytes,0,len2);
System.out.println(str2);
int len3=fis.read(bytes);
System.out.println("第三次读取的数据个数"+len3);
String str3=new String(bytes,0,len3);
System.out.println(str3);
// 当没有数据可以读取时 fis.read(bytes)的返回值为-1
int len4=fis.read(bytes);
System.out.println("第四次读取的数据个数"+len4);// -1
// 3.释放资源
fis.close();
}
}
3、利用FileInputStream、FileOutStream进行文件拷贝
通过边读边写的思想,先将文件读取到程序中,再将程序中的数据写到另一个文件中
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class test6 {
public static void main(String[] args) throws IOException {
// 1.创建对象
FileInputStream fis=new FileInputStream("D:\\测试安全\\d.txt");
FileOutputStream fos=new FileOutputStream("d.txt");
// 2.读数据
// 依次读取读取一个数据 指针后移 返回值是字符对应的ASCII码值 如果全部读取完 返回-1
// ascii码表中不存在acsii码值为-1的字符
int read;
while ((read=fis.read())!=-1) {
// 3.写数据
// d.txt文件不存在 会创建文件并写入数据
// 将读取的数据写到文件中
fos.write(read);
}
// 4.释放资源
// 先开的流最后释放
fos.close();
fis.close();
}
}
当拷贝的文件过大时 我们可以通过一次读取多个数据进行读取 提高速度
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class test6 {
public static void main(String[] args) throws IOException {
// 1.创建对象
FileInputStream fis=new FileInputStream("D:\\测试安全\\d.txt");
FileOutputStream fos=new FileOutputStream("d.txt");
// 2.读数据
// 依次读取读取一个数据 指针后移 返回值是字符对应的ASCII码值 如果全部读取完 返回-1
// ascii码表中不存在acsii码值为-1的字符
int len;
byte [] bytes=new byte[1024];
while ((len=fis.read(bytes))!=-1) {
// 3.写数据
// d.txt文件不存在 会创建文件并写入数据
// 将读取的数据写到文件中
fos.write(bytes,0,len);
}
// 4.释放资源
// 先开的流最后释放
fos.close();
fis.close();
}
}
4、利用FileInputStream、FileOutStream进行文件夹拷贝
无论是图片、word、excel、视频等都可以进行复制
如果是文件则直接拷贝 如果是文件夹则需要递归
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class 复制文件夹 {
public static void main(String[] args) throws IOException {
// 将f1文件的内容拷贝到f2中
File f1=new File("D:\\测试安全");
File f2=new File("D:\\测试安全复制版");
copydir(f1,f2);
}
private static void copydir(File f1, File f2) throws IOException {
// 如果f2文件夹存在则不做任何处理 如果不存在 则创建文件夹
f2.mkdirs();
// 获取f1文件夹下的所有内容
File[] files = f1.listFiles();
for (File file : files) {
// 判断是否为文件
// 如果是文件则边读边写 直接赋值
if(file.isFile()){
// 创建该file文件的字节输入流 用来读取file文件内容到程序中
FileInputStream fis=new FileInputStream(file);
// 创建该file文件的字节输出流 用来将程序的内容写到读取new File(f2,file.getName())路径表示的文件中
FileOutputStream fos=new FileOutputStream(new File(f2,file.getName()));
// 创建字节数组 用来一次最多读取1k个字节 提高读取速度
byte [] bytes=new byte[1024*10];
// 实际读取的字节数
int len;
while ((len=fis.read(bytes))!=-1) {
// 写数据 读多少写多少
fos.write(bytes,0,len);
}
// 关闭该file文件的字节输出流
fos.close();
// 关闭该file文件的字节输入流
fis.close();
}
// 如果不是文件则递归
else {
copydir(file,new File(f2,file.getName()));
}
}
}
}
5、利用FileInputStream、FileOutStream进行文件夹文件加密
通过字节流读取文件和写入文件 都是写入对应的编码值
对文件进行加密时 我们就可以将读取文件a得到的字节数据(编码值)进行改变写入文件b
对文件b进行解密时我们就可以将读取文件b得到的字节数据(编码值)进行改变使之变成与读取文件a得到的字节数据一样的数据写入文件c
如何实现?
之间我们学习过异或运算 数1与另一个数2异或两次即可得到原来的数1
我们就可以将数1与另一个数2异或一次看成加密过程
将数1与另一个数2的结果再与数2异或的过程看成解密过程
加密:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class 加密 {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("D:\\测试安全\\c\\机器人.png");
FileOutputStream fos=new FileOutputStream("D:\\测试安全\\c\\机器人2.png");
int read;
// 加密过程
while ((read=fis.read())!=-1){
fos.write(read^2);
}
fos.close();
fis.close();
}
}
解密:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class 解密 {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("D:\\测试安全\\c\\机器人2.png");
FileOutputStream fos=new FileOutputStream("D:\\测试安全\\c\\机器人3.png");
int read;
// 解密过程
while ((read=fis.read())!=-1){
fos.write(read^2);
}
fos.close();
fis.close();
}
}
6、io流字符集
io流字符集包括ASCII字符集、GBK字符集、Unicode字符集
数据存储在计算机的形式都是补码!!!
(1)、ASCII字符集
ASCII字符集没有中文的编码
(2)、GBK字符集
存储英文和ASCII字符集存储英文的格式一样
(3)、Unicode字符集
为了统一各个国家的编码 创建了Unicode字符集
Unicode字符集包含了以下三种编码规则:UTF-8、UTF-16、UTF-32
现在我们详细介绍UTF-8的编码规则:
在UTF-8的编码规则下,英文占一个字节,中文占3个字节(且第一个字节的首位是1)
如果是英文,找到Unicode字符集下的编码值后在前面加0即可得到它存储在计算机的值
如果是中文,找到Unicode字符集下的编码值后将其按4 6 6 分成3部分,第一部分前面加1110,第二部分前面加10,第三部分前面加10,即可得到它存储在计算机的值
(4)、字符集小结
(5)、产生乱码的原因
1、读取数据时没有读完整个汉字
因为一个汉字按GBK字符集需要2个字节的存储空间、按Unicode字符集需要3个字节的存储空间,而字节流每次读取一个字节,就会导致汉字未读完
2、解码规则和编码规则不一致
因为一个汉字按GBK字符集需要2个字节的存储空间、按Unicode字符集需要3个字节的存储空间,如果按Unicode字符集中UTF-8编码而用GBK字符集进行解码就会将3个字节拆分成2个字节、1个字节进行解码
(6)、解决乱码
(7)、编码
在idea中默认的编码方式是UTF-8,在eclipse默认的编码方式是GBK
语法1:
字符串.getBytes(); 使用平台默认的方式进行编码
语法2:
字符串.getBytes(指定字符集); 使用指定字符集进行编码
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class test8 {
public static void main(String[] args) throws UnsupportedEncodingException {
String str1="ok世界";
// 系统默认的编码方式进行编码
byte[] bytes1 = str1.getBytes();
System.out.println(Arrays.toString(bytes1));
/*
[111, 107, -28, -72, -106, -25, -107, -116]
其中111表示o对应的Unicode编码
107表示k对应的Unicode编码
-28 -72 -106表示世对应的Unicode编码
-25 -107 -116表示界对应的Unicode编码
*/
String str2="ok世界";
// 指定的编码方式进行编码
byte[] bytes2 = str2.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));
/*
[111, 107, -54, -64, -67, -25]
其中111表示o对应的Unicode编码
107表示k对应的Unicode编码
-54 -64表示世对应的Unicode编码
-67 -25表示界对应的Unicode编码
*/
}
}
(8)、解码
在idea中默认的解码方式是UTF-8,在eclipse默认的解码方式是GBK
语法1:
new 字符串(字节数组); 使用平台默认的方式进行编码
语法2:
new 字符串(字节数组,指定字符集); 使用指定字符集进行编码
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class test8 {
public static void main(String[] args) throws UnsupportedEncodingException {
String str1="ok世界";
// 系统默认的编码方式进行编码
byte[] bytes1 = str1.getBytes();
System.out.println(Arrays.toString(bytes1));
/*
[111, 107, -28, -72, -106, -25, -107, -116]
其中111表示o对应的Unicode编码
107表示k对应的Unicode编码
-28 -72 -106表示世对应的Unicode编码
-25 -107 -116表示界对应的Unicode编码
*/
// 系统默认的编码方式进行解码
String s1 = new String(bytes1);
System.out.println(s1);
// ok世界
String str2="ok世界";
// 指定的编码方式进行编码
byte[] bytes2 = str2.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));
/*
[111, 107, -54, -64, -67, -25]
其中111表示o对应的Unicode编码
107表示k对应的Unicode编码
-54 -64表示世对应的Unicode编码
-67 -25表示界对应的Unicode编码
*/
// 指定编码方式进行解码
String s2 = new String(bytes2,"GBK");
System.out.println(s2);
// ok世界
// 如果解码方式与编码方式不一致则会出现乱码
// bytes1是通过Unicode的UTF-8进行编码 而采用GBK进行解码
String s3 = new String(bytes1,"GBK");
System.out.println(s3);
// ok涓栫晫
}
7、字符流概要
8、字符流之FileReader
(1)、概念
操作本地文件的字符输入流 可以将本地文件的数据读取到程序中
(2)、步骤+细节
1、创建对象(让程序和文件之间建立一个通道)
细节:如果文件不存在则会报错
语法1:
FileReader fr=new FileReader(字符串表示的路径);
语法2:
FileReader fr=new FileReader(文件对象表示的路径);
2、读数据
语法1:无参read方法 一次读取一个数据,返回值为读取的数据(是数据对应的码值),读到末尾返回-1
字符流对象.read();
语法2:有参read方法 一次读取多个数据,返回值为读取的数据(是数据对应的码值),读到末尾返回-1
字符流对象.read(字符数组);
细节:
而字节流通通都是一个字节一个字节读取
3、释放资源(断开程序和文件之间建立一个通道)
防止java程序占用资源 使得在其它程序中可以打开
语法:
字符流对象.close();
(3)、无参read方法读取数据
import java.io.FileReader;
import java.io.IOException;
public class FileReader字符流 {
public static void main(String[] args) throws IOException {
// 1.创建对象 字符串的形式表示路径
FileReader fr=new FileReader("a.txt");
// 2.读取数据
// 字符流的底层原理还是字节流 读取出的数据还是字符对应的码值的形式
// 一次读取一个字节 遇到中文读取3个字节
int ch;
while ((ch= fr.read())!=-1) {
System.out.print((char)ch);
}
/*
java 你好星期六
我与我周旋久 宁作我
*/
// 3.释放资源
fr.close();
}
}
(4)、有参read方法读取数据
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
public class FileReader字符流1 {
public static void main(String[] args) throws IOException {
// 1.创建对象 字符串的形式表示路径
FileReader fr=new FileReader("a.txt");
// 2.读取数据
// 字符流的底层原理还是字节流 读取出的数据还是字符对应的码值的形式
// 一次读取一个字节 遇到中文读取3个字节
// 此时len表示读取的数据个数 而不是数据
int len;
// 定义一个长度为2的数组 数组的长度决定了每次最多读取的个数
// 每次读取的数据都会存放在数组中 数组是重复利用的 每次存放的数据都会覆盖原来的数据
char [] c=new char[2];
while ((len= fr.read(c))!=-1) {
// 创建字符串c部分内容的字符串
String str=new String(c,0,len);
System.out.print(str);
}
/*
java 你好星期六
我与我周旋久 宁作我
*/
// 3.释放资源
fr.close();
}
}
9、字符流之FileWrite
(1)、构造方法
当append为true 表示打开续写开关 默认情况下是关闭续写开关
(2)、成员方法(写入数据的5种方式)
写一个字符:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileWrite字符流2 {
public static void main(String[] args) throws IOException {
// 1.创建对象 字符串的形式表示路径
// true表示文件不是覆盖写 是追加写
FileWriter fw=new FileWriter("a.txt",true);
// 2.写入数据
// fw.write(字符编码);
// 一次写入一个字符(无论是英文字符还是汉字字符)
// write方法会根据字符集的编码方式进行编码 如果是汉字则为3个字节 英文则为一个字节 并把编码之后的数据写到文件中
fw.write(97);
fw.write(25105);
// 3.释放资源
fw.close();
}
写一个字符串:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileWrite字符流2 {
public static void main(String[] args) throws IOException {
// 1.创建对象 字符串的形式表示路径
// true表示文件不是覆盖写 是追加写
FileWriter fw=new FileWriter("a.txt",true);
// 2.写入数据
// fw.write(字符串);
// 一次写入一个字符串
// 英文状态下的标点符号是英文字符 中文状态下的标点符号是汉字字符
fw.write("java你好!");
// 3.释放资源
fw.close();
}
}
写一个字符串的一部分:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileWrite字符流2 {
public static void main(String[] args) throws IOException {
// 1.创建对象 字符串的形式表示路径
// true表示文件不是覆盖写 是追加写
FileWriter fw=new FileWriter("a.txt");
// 2.写入数据
// fw.write(字符串,开始索引,总个数);
// 一次写入一个字符串的一部分
// 英文状态下的标点符号是英文字符 中文状态下的标点符号是汉字字符
fw.write("java你好!",0,4);
// 3.释放资源
fw.close();
}
}
写一个字符数组:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileWrite字符流2 {
public static void main(String[] args) throws IOException {
// 1.创建对象 字符串的形式表示路径
// true表示文件不是覆盖写 是追加写
FileWriter fw=new FileWriter("a.txt");
// 2.写入数据
// fw.write(字符数组);
// 一次写入一个字符数组
// 英文状态下的标点符号是英文字符 中文状态下的标点符号是汉字字符
char [] chs={'j','a','v','a','你','好'};
fw.write(chs);
// 3.释放资源
fw.close();
}
}
(3)、书写细节
10、字符流和字节流的使用场景
11、缓冲流概要
为了提高字节流和字符流的效率 java设计了缓冲流
但是缓冲流是对字节流和字符流进行包装 真正读取和写入数据的还是字节流和字符流
12、缓冲流之字节缓冲流
字节缓冲流的使用与字节缓冲流的使用很相似
(1)、构造方法
利用字节缓冲流进行拷贝:
一次读取一个字节
import java.io.*;
public class 字节缓冲流拷贝 {
public static void main(String[] args) throws IOException {
// 1.创建字节缓冲流
BufferedInputStream bis= new BufferedInputStream(new FileInputStream("D:\\测试安全\\d.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\测试安全\\dd.txt"));
// 2.循环读取并写入数据
int len;
while ((len=bis.read())!=-1){
bos.write(len);
}
// 3.关闭流(不需要关闭字节输入流、字节输出流 只需要关闭字节缓冲流)
bos.close();
bis.close();
}
}
利用字节缓冲流进行拷贝:
一次读取多个字节:
import java.io.*;
public class 字节缓冲流拷贝 {
public static void main(String[] args) throws IOException {
// 1.创建字节缓冲流
BufferedInputStream bis= new BufferedInputStream(new FileInputStream("D:\\测试安全\\d.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\测试安全\\ddd.txt"));
// 2.循环读取并写入数据
// 一次读取多个字节
// len表示每次读取的实际个数
int len;
// 创建bytes 用来存放每次读取的数据的码值 20表示每次读取最多的个数
byte [] bytes=new byte[20];
while ((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
// 3.关闭流(不需要关闭字节输入流、字节输出流 只需要关闭字节缓冲流)
bos.close();
bis.close();
}
13、缓冲流之字符缓冲流
(1)、构造方法
(2)、特有方法
细节:
readLine()方法读取数据 是一次读取一行数据 遇到回车换行就停止
且不会将回车换行读取到内存中 如果使用println进行打印则会一行一行输出
如果使用print进行打印则不会一行一行输出 会粘在一起
import java.io.*;
public class 字符缓冲流拷贝 {
public static void main(String[] args) throws IOException {
// 1.创建字节缓冲流
BufferedReader br= new BufferedReader(new FileReader("D:\\测试安全\\c.txt"));
BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\测试安全\\cc.txt"));
// 2.循环读取并写入数据
// readLine()方法读取数据 是一次读取一行数据 遇到回车换行就停止
// 且不会将回车换行读取到内存中
String line;
// 当读取完成line的返回值为null
while ((line=br.readLine())!=null){
System.out.println(line);
}
// 3.关闭流(不需要关闭字节输入流、字节输出流 只需要关闭字节缓冲流)
br.close();
}
}
细节2:
换行 这是BufferedWriter特有的方法 在之前通过字节流或字符流换行 对于不同的操作系统书写的方式不一样
而BufferedWriter只需要通过newLine方法即可在不同的操作系统下实现换行
细节3:
如果要实现续写 则需要在创建FileWriter时加上true 不是在创建BufferedWriter时添加true
14、缓冲流小结
15、拷贝文件方式总结
字节基本流 一次读取一个字节:
import java.io.*;
public class 拷贝 {
public static void main(String[] args) throws IOException {
// 字节基本流 一次读取一个字节
// 1.创建对象
FileInputStream fis=new FileInputStream("D:\\测试安全\\d.txt");
FileOutputStream fos=new FileOutputStream("D:\\测试安全\\dd.txt");
// 2.读数据
// 依次读取读取一个数据 指针后移 返回值是字符对应的ASCII码值 如果全部读取完 返回-1
// ascii码表中不存在acsii码值为-1的字符
int len;
while ((len=fis.read())!=-1) {
// 3.写数据
// d.txt文件不存在 会创建文件并写入数据
// 将读取的数据写到文件中
fos.write(len);
}
// 4.释放资源
// 先开的流最后释放
fos.close();
fis.close();
}
}
字节基本流 一次读取一个字节数组:
import java.io.*;
public class 拷贝 {
public static void main(String[] args) throws IOException {
// 字节基本流 一次读取一个字节数组
// 1.创建对象
FileInputStream fis=new FileInputStream("D:\\测试安全\\d.txt");
FileOutputStream fos=new FileOutputStream("D:\\测试安全\\dd.txt");
// 2.读数据
// 依次读取读取一个数据 指针后移 返回值是字符对应的ASCII码值 如果全部读取完 返回-1
// ascii码表中不存在acsii码值为-1的字符
int len;
byte [] bytes=new byte[8192];
while ((len=fis.read(bytes))!=-1) {
// 3.写数据
// d.txt文件不存在 会创建文件并写入数据
// 将读取的数据写到文件中
fos.write(bytes,0,len);
}
// 4.释放资源
// 先开的流最后释放
fos.close();
fis.close();
}
}
字节缓冲流 一次读取一个字节:
import java.io.*;
public class 拷贝 {
public static void main(String[] args) throws IOException {
// 字节缓冲流 一次读取一个字节
// 1.创建字节缓冲流
BufferedInputStream bis= new BufferedInputStream(new FileInputStream("D:\\测试安全\\d.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\测试安全\\ddd.txt"));
// 2.循环读取并写入数据
int len;
while ((len=bis.read())!=-1){
bos.write(len);
}
// 3.关闭流(不需要关闭字节输入流、字节输出流 只需要关闭字节缓冲流)
bos.close();
bis.close();
}
}
字节缓冲流 一次读取一个字节数组:
import java.io.*;
public class 拷贝 {
public static void main(String[] args) throws IOException {
// 字节缓冲流 一次读取一个字节数组
// 1.创建字节缓冲流
BufferedInputStream bis= new BufferedInputStream(new FileInputStream("D:\\测试安全\\d.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("D:\\测试安全\\ddd.txt"));
// 2.循环读取并写入数据
// 一次读取多个字节
// len表示每次读取的实际个数
int len;
// 创建bytes 用来存放每次读取的数据的码值
byte [] bytes=new byte[8192];
while ((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
// 3.关闭流(不需要关闭字节输入流、字节输出流 只需要关闭字节缓冲流)
bos.close();
bis.close();
}
}
16、字符转化流
(1)、概念
转化流是字节流和字符流之间的桥梁
(2)、利用转化流按照指定的字符编码读取数据
语法:FileReader 对象名=new FileReader(路径, Charset.forName("字符集"));
为了解决这个问题 我们可以指定字符输入流的字符集 使之与文本文件的字符集保持一致
(3)、利用转化流按照指定的字符编码写入数据
语法:FileWriter 对象名=new FileWriter(路径, Charset.forName("字符集"));
为了解决这个问题 我们可以指定字符输出流的字符集 使之与文本文件的字符集保持一致
(4)、利用字节流读取文本文件中的每一行数据
语法:
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(路径)));
详细写法:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class 字节流读取文本文件 {
public static void main(String[] args) throws IOException {
// 创建字节输入流
FileInputStream fis=new FileInputStream("D:\\测试安全\\e.txt");
// 将字节输入流转化为字符输入流 使之能读取文本文件中的数据 同时指定字符输入流的编码规则为GBK
InputStreamReader isr=new InputStreamReader(fis, Charset.forName("GBK"));
// 将字符输入流包装成字符缓冲流 使之能一行一行读取数据
BufferedReader br=new BufferedReader(isr);
System.out.println(br.readLine());
isr.close();
}
}
简便写法:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class 字节流读取文本文件 {
public static void main(String[] args) throws IOException {
// 将字节输入流转化为字符输入流 使之能读取文本文件中的数据 同时指定字符输入流的编码规则为GBK
// 将字符输入流包装成字符缓冲流 使之能一行一行读取数据
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("D:\\测试安全\\e.txt"), Charset.forName("GBK")));
System.out.println(br.readLine());
br.close();
}
}
(5)、小结
16、序列化流
只有字节流才有序列化流,字符流没有序列化流
(1)、概念
通过序列化流可以将java对象写在本地文件中
(2)、构造方法/成员方法
通过序列化流可以将java对象写在本地文件中
构造方法语法:
ObjectOutputStream 对象名称=new ObjectOutputStream(new FileOutputStream(路径));
成员方法语法:
序列化流对象.writeObject(要写入的java对象);
细节:
要写入的java对象必须实现Serializable接口才能被写入本地文件
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class 序列化流 {
public static void main(String[] args) throws IOException {
// 1.创建对象
Student s = new Student("zhangsan", 23);
// 2.创建序列化流
// 需要传入字节输出流作为参数
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\测试安全\\ee.txt"));
// 3.写对象到本地文件
oos.writeObject(s);
// 4.释放资源
oos.close();
}
}
// Student类必须实现Serializable接口才能被写入本地文件
// Serializable没有任何抽象方法 因此Student类必须实现Serializable接口时不需要重写任何方法
class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
17、反序列化流
只有字节流才有反序列化流,字符流没有反序列化流
(1)、概念
通过序列化流可以将本地文件中的java对象读取到程序中
(2)、构造方法/成员方法
构造方法语法:
ObjectInputStream 对象名称=new ObjectInputStream(new FileInputStream(路径));
成员方法语法:
序列化流对象.readObject();
18、打印流概要
打印流是高级流,只有输出流才有打印流
因此打印流不能从文件读取数据 只能打印数据到文件中
19、打印流之字节打印流
(1)、构造方法
重点掌握第1、2种方法
(2)、特有方法
特有方法可以将数据原样打印在文件上
常规方法是将码值为该数字对应的字符打印在文件中
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
public class 打印流 {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
// 1.创建字节打印流的对象
PrintStream ps=new PrintStream(new FileOutputStream("a.txt"),true,"UTF-8");
// 2.打印数据
ps.println(97);// 打印任意数据 包括了三步:写出、自动刷新、换行
ps.print("臣妾要告发熹贵妃私通");// 打印任意数据 不换行
ps.printf("那年杏花微雨 你说你是%s","果郡王");// 打印含有占位符的语句 不换行
// 3.关闭资源
ps.close();
}
}
19、打印流之字符打印流
字符打印流与字节打印流的用法很相似
(1)、构造方法
(2)、特有方法
特有方法可以将数据原样打印在文件上
import java.io.*;
public class 打印流 {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
// 1.创建字节打印流的对象
// 如果自动刷新为false 则不会将内容立刻打印在文件上
PrintWriter ps=new PrintWriter(new FileOutputStream("a.txt"),true);
// 2.打印数据
ps.write(97);// 普通打印
ps.println();
ps.println(97);// 打印任意数据 包括了三步:写出、自动刷新、换行
ps.print("这福气给你要不要啊");// 打印任意数据 不换行
ps.printf("我儿%s必定高中","长柏");// 打印含有占位符的语句 不换行
// 3.关闭资源
ps.close();
/*补充
在Java中,当使用I/O流(如FileOutputStream、PrintWriter等)进行文件操作时,数据通常不是直接写入文件的。
相反,它们首先被写入到一个内部缓冲区中,以提高写入效率。当你调用写入方法(如write(), println(), print(), printf()等)时,数据实际上是被放入这个缓冲区中的。
只有当缓冲区满了,或者当你显式地调用flush()方法,或者关闭流(这通常会自动调用flush()方法)时,缓冲区中的数据才会被真正写入到文件或目标输出中。
在你的例子中,你创建了一个PrintWriter对象,并指定了autoFlush参数为false,这意味着每次调用写入方法后不会自动刷新缓冲区。
然后,你写入了一些数据,但你没有调用flush()方法,也没有关闭流。
由于你没有关闭流(即没有调用ps.close()),也没有调用flush()方法,缓冲区中的数据就一直在内存中,没有被写入到文件a.txt中。这就是为什么你打开文件时看不到任何内容的原因。
但是,当你调用ps.close()时,PrintWriter对象的close()方法会被调用。
这个方法不仅关闭了流,还会确保所有待写入的数据都被刷新(即写入)到目标文件中。这就是为什么在调用ps.close()之后,你可以在文件中看到写入的数据。
所以,为了避免数据丢失或看不到写入的内容,你应该始终在完成写入操作后关闭流,或者使用flush()方法手动刷新缓冲区。
但在实际开发中,更常见的做法是使用try-with-resources语句来自动管理资源(包括流的关闭),这样可以确保即使发生异常,资源也能被正确关闭。*/
}
}