IO总结之文件字节、字符输入输出流、缓冲流、转化流(乱码)(二)
IO
相关总结FileInputStream
和FileOutputStream
使用FileReader
和FileWriter
使用- 缓冲流
BufferedReader
和BufferedWrite
r(上层流)使用 - 文件字节拷贝
- 文件字符拷贝
- 文件目录拷贝以及递归的删除文件目录
- 转换流(乱码问题)
- 总结图
IO
相关总结
分类
数据源
data source
,提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网络连接、IO
设备。- 数据源就像水箱,流就像水管中流着的水流,程序就是我们最终的用户。 流 是一个抽象、动态的概念,是一连串连续动态的数据集合。
IO
流原理
IO流体系
总体概况
FileInputStream
和FileOutputStream
使用
文件字节内容的读取和写入FileInputStream
import java.io.*;
public class FileInputStremTest {
public static void main(String[] args) {
File path = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt");
FileInputStream is = null; //为了使finally中能够关闭
try {
is = new FileInputStream(path);
byte[] data = new byte[20]; //循环中每一次读取的长度
int len = 0; //实际读取的长度
while(-1 != (len = is.read(data))) {
String info = new String(data, 0, len); 字符数组转成字符串 把字节数组构建出来
System.out.println(info); //dfs.txt中内容: "123wen汉"
System.out.println("文件长度" + len); //输出实际读取的长度
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在!");
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取文件失败!");
}finally { //一般在finally中关闭流
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("关闭文件流失败!");
}
}
}
}
}
效果:
然后就是文件的写出,使用FileOutputStream
,这里要注意几点 :
FileOutputStream(path,true)
,true
是追加,默认false
是覆盖os.flush();
//一般写出之后强制刷新出去(从流的管道) 为什么要刷新呢,因为相当于一根管道,管道没有满就不会出去,所以我们要强制刷新一下。- 注意
str.getBytes()
的使用
import java.io.*;
public class FileOutputStreamTest {
public static void main(String[] args) {
File path = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt");
FileOutputStream os = null;
try {
os = new FileOutputStream(path,true); // (File file boolean append) //true 追加 ,false 覆盖(默认)
String str = "FileOutputStream is very good!"; //写出到out.txt
byte[] data = str.getBytes(); //将字符串转成字节数组
os.write(data,0,data.length);
os.flush(); //强制刷新出去(从流的管道)
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在!");
} catch (IOException e) {
System.out.println("文件写入失败!");
e.printStackTrace();
} finally {
if(null != os) {
try {
os.close();
} catch (IOException e) {
System.out.println("关闭输出流失败!");
e.printStackTrace();
}
}
}
}
}
FileReader
和FileWriter
使用
和字节输入输出差不多。
import java.io.*;
public class FileReaderTest {
public static void main(String[] args) {
File src = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt");
Reader reader = null;
try {
reader = new FileReader(src);
char[] flush = new char[1024];
int len = 0;
while(-1 != (len = reader.read(flush))) {
//字符数组转字符串
String str = new String(flush, 0, len);
System.out.println(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在!");
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取文件失败!");
}finally {
if(null != reader) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件关闭失败!");
}
}
}
}
}
文件字符输出流也有几个要注意的地方:
wr.write(str);
,注意Writer可以直接写入数组,不需要转成字符数组;wr.append("hello");
可以直接使用append
方法;- 注意
linux
中换行/r
和/n
的使用;(在unix
内核系统中换行是\n
,在windows
中换行要使用\r\n
);
import java.io.*;
public class FileWriterTest {
public static void main(String[] args) {
File dest = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt");
Writer wr = null;
try {
wr = new FileWriter(dest,true); //追加
String str = "锄禾日当午\r\n码农真辛苦\r\n一本小破书\r\n一读一上午\r\n";
wr.write(str); //注意Writer可以直接写入数组,不需要转成字符数组
wr.append("加油努力!");
wr.flush();
}catch(FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件写入失败!");
}catch (IOException e) {
e.printStackTrace();
System.out.println("文件不存在!");
}finally {
if(null != wr) {
try {
wr.close();
} catch (IOException e) {
System.out.println("文件关闭失败!");
e.printStackTrace();
}
}
}
}
}
缓冲流BufferedInputStream
和BufferedOutputStream
(上层流)的使用
要注意的是: 放在外面的流要是抽象的InputStream
和OutputStream
,因为使用了多个流;
import java.io.*;
/**
* 字节操作 + 缓冲流
*/
public class BufferedInputStreamTest {
public static void main(String[] args) {
File path = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt");
InputStream is = null; //注意这里要使用超类 上转型 为了下面缓冲流的使用
try {
is = new BufferedInputStream(new FileInputStream(path));
byte[] data = new byte[20]; //循环中每一次读取的长度
int len = 0; //实际读取的长度
while (-1 != (len = is.read(data))) {
String info = new String(data, 0, len); 字符数组转成字符串 把字节数组构建出来
System.out.println(info); //dfs.txt中内容: "123wen汉"
System.out.println("文件长度" + len); //输出实际读取的长度
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在!");
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取文件失败!");
} finally { //一般在finally中关闭流
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("关闭文件流失败!");
}
}
}
}
}
import java.io.*;
public class BufferedOutputStreamTest {
public static void main(String[] args) {
File path = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt");
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(path,true)); // (File file boolean append) //true 追加 ,false 覆盖(默认)
String str = "FileOutputStream is very good!"; //写出到out.txt
byte[] data = str.getBytes(); //将字符串转成字节数组
os.write(data,0,data.length);
os.flush(); //强制刷新出去(从流的管道)
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在!");
} catch (IOException e) {
System.out.println("文件写入失败!");
e.printStackTrace();
} finally {
if(null != os) {
try {
os.close();
} catch (IOException e) {
System.out.println("关闭输出流失败!");
e.printStackTrace();
}
}
}
}
}
缓冲流BufferedReader
和BufferedWriter
(上层流)使用
BufferedReader
包裹的FileReader
,BufferedWriter
包裹的是FileWriter
;- 注意
readLine()
和newLine()
等新方法的使用; - 注意如果有新方法,就不能使用多态(也就是使用
Reader
和Writer
);
import java.io.*;
public class BufferdReaderTest {
public static void main(String[] args) {
File src = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt");
BufferedReader reader = null;//有新方法,不用Reader
try {
reader = new BufferedReader(new FileReader(src));
/**char[] flush = new char[1024];
int len = 0;
while (-1 != (len = reader.read(flush))) {
//字符数组转字符串
String str = new String(flush, 0, len);
System.out.println(str);
}*/
//使用新增方法 不能发生多态
String line = null;
while(null != (line=reader.readLine())){ //注意是一行一行的读
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在!");
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取文件失败!");
} finally {
if (null != reader) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件关闭失败!");
}
}
}
}
}
import java.io.*;
public class BufferedWriterTest {
public static void main(String[] args) {
File dest = new File("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt");
BufferedWriter wr = null;//有新增的方法 如newLine,所以不能使用多态
try {
wr = new BufferedWriter(new FileWriter(dest,true)); //追加
String str = "锄禾日当午\r\n码农真辛苦\r\n一本小破书\r\n一读一上午\r\n";
wr.write(str);
wr.newLine(); //新的一行
wr.append("加油努力!");
wr.flush();
}catch(FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件写入失败!");
}catch (IOException e) {
e.printStackTrace();
System.out.println("文件不存在!");
}finally {
if(null != wr) {
try {
wr.close();
} catch (IOException e) {
System.out.println("文件关闭失败!");
e.printStackTrace();
}
}
}
}
}
文件字节拷贝
这个比较简单,只需要通过程序将读入和写出联系起来即可,注意先打开的流后关闭;
import java.io.*;
public class FileCopyTest {
public static void main(String[] args) {
//确保src存在且可读(不能是文件夹) dest 可以不存在
String src = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt";
String dest = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt";
try {
copyFile(src, dest);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 文件拷贝
* @param srcPath
* @param destPath
* @throws FileNotFoundException
* @throws IOException
*/
public static void copyFile(String srcPath,String destPath) throws FileNotFoundException,IOException {
File src = new File(srcPath);
File dest = new File(destPath);
if(!src.isFile()) {
throw new IOException("只能拷贝文件!");
}
//dest为已经存在的文件夹,不能建立与文件夹同名的文件
if(dest.isDirectory()){
throw new IOException(dest.getAbsolutePath() + "不能建立与文件夹同名的文件!");
}
FileInputStream is = new FileInputStream(src);
FileOutputStream os = new FileOutputStream(dest);
byte[] bytes = new byte[1024];
int len = 0;
while(-1 != (len = is.read(bytes))) {
os.write(bytes, 0, len);
}
os.flush(); //强制刷出
//先打开的后关闭
os.close();
is.close();
}
}
使用缓冲改进:
import java.io.*;
public class FileCopy2Test {
public static void main(String[] args) {
//确保src存在且可读(不能是文件夹) dest 可以不存在
String src = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt";
String dest = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt";
try {
copyFile(src, dest);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 文件拷贝
* @param srcPath
* @param destPath
* @throws FileNotFoundException
* @throws IOException
*/
public static void copyFile(String srcPath,String destPath) throws FileNotFoundException,IOException {
File src = new File(srcPath);
File dest = new File(destPath);
if(!src.isFile()) {
throw new IOException("只能拷贝文件!");
}
//dest为已经存在的文件夹,不能建立与文件夹同名的文件
if(dest.isDirectory()){
throw new IOException(dest.getAbsolutePath() + "不能建立与文件夹同名的文件!");
}
InputStream is = new BufferedInputStream(new FileInputStream(src));
OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
byte[] bytes = new byte[1024];
int len = 0;
while(-1 != (len = is.read(bytes))) {
os.write(bytes, 0, len);
}
os.flush(); //强制刷出
//先打开的后关闭
os.close();
is.close();
}
}
文件字符拷贝(仅限于字符的纯文本)
这个和上面的大同小异 :
import java.io.*;
public class FileCopy2Test {
public static void main(String[] args) {
// 确保src存在且可读(不能是文件夹) dest 可以不存在
String src = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt";
String dest = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt";
try {
copyFile(src, dest);
} catch (FileNotFoundException e) {
System.out.println("文件不存在!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("文件写入失败或者关闭流失败!");
e.printStackTrace();
}
}
/**
* 文件拷贝
* @param srcPath
* @param destPath
* @throws FileNotFoundException
* @throws IOException
* @return;
*/
public static void copyFile(String srcPath, String destPath) throws FileNotFoundException, IOException {
File src = new File(srcPath);
File dest = new File(destPath);
if (!src.isFile()) {
throw new IOException("只能拷贝文件!"); //自己手动抛出异常
}
if(dest.isDirectory()){
throw new IOException(dest.getAbsolutePath() + "不能建立与文件夹同名的文件!");
}
Reader re = new FileReader(src);
Writer wr = new FileWriter(dest);
char[] flush = new char[100];
int len = 0;
while (-1 != (len = re.read(flush))) {
//System.out.println(new String(flush,0,len));
wr.write(flush, 0, len);
}
wr.flush(); // 强制刷出
// 先打开的后关闭
wr.close();
re.close();
}
}
使用缓冲改进:
import java.io.*;
public class FileCopyChar2Test {
public static void main(String[] args) {
// 确保src存在且可读(不能是文件夹) dest 可以不存在
String src = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt";
String dest = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt";
try {
copyFile(src, dest);
} catch (FileNotFoundException e) {
System.out.println("文件不存在!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("文件写入失败或者关闭流失败!");
e.printStackTrace();
}
}
/**
* 文件拷贝
* @param srcPath
* @param destPath
* @throws FileNotFoundException
* @throws IOException
* @return;
*/
public static void copyFile(String srcPath, String destPath) throws FileNotFoundException, IOException {
File src = new File(srcPath);
File dest = new File(destPath);
if (!src.isFile()) {
throw new IOException("只能拷贝文件!"); //自己手动抛出异常
}
if(dest.isDirectory()){
throw new IOException(dest.getAbsolutePath() + "不能建立与文件夹同名的文件!");
}
BufferedReader re = new BufferedReader(new FileReader(src));
BufferedWriter wr = new BufferedWriter(new FileWriter(dest));
/**char[] flush = new char[100];
int len = 0;
while (-1 != (len = re.read(flush))) {
//System.out.println(new String(flush,0,len));
wr.write(flush, 0, len);
}
*/
String line = null;
while(null != (line = re.readLine())){
wr.write(line);
wr.newLine(); //可以在文件中使用"/r/n" 也可以使用这样的方法
}
wr.flush(); // 强制刷出
// 先打开的后关闭
wr.close();
re.close();
}
}
文件目录拷贝以及递归的删除文件目录
文件目录的拷贝:
- 如果
src
(源)是文件的话,就调用文件拷贝的函数(上面写了)。 - 如果是目录的话,就首先
mkdirs
,创建dest
目录,然后把src目录下的每个文件递归的拷贝到dest
中。
import java.io.*;
/**
* 文件夹的拷贝和删除
* 1.如果是文件,直接IO流拷贝
* 2.如果是文件夹,就创建
* 3.递归的使用(递归查找子孙级)
* A
* |
* / \
* a.txt b
* |
* b.txt
*/
public class CopyDir {
public static void main(String[] args) {
String srcPath = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/from";
String destPath = "/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/to";
// copyDir(srcPath, destPath);
deleteFile(new File(destPath));
}
public static void copyDir(String srcPath,String destPath) {
File src = new File(srcPath);
File dest = new File(destPath);
copyDir(src,dest);
}
public static void copyDir(File src,File dest) {
if(src.isDirectory()) {//是文件夹的话要先建一个srcPath 如果是文件的直接拷贝
dest = new File(dest,src.getName()); //dest是父目录 然后我先创建你的src
if(dest.getAbsolutePath().contains(src.getAbsolutePath())){ //子目录的文件路径名称包含父目录
System.out.println("父目录不能拷贝到子目录中!");
return;
}
}
copyDirDetail(src,dest);
}
public static void copyDirDetail(File src,File dest) {
if(src.isFile()) { //如果是文件的话就直接拷贝
try {
copyFile(src, dest); //调用下面的文件拷贝的方法(上面写过,下面的工具类也有)
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else if(src.isDirectory()) { //如果是目录
dest.mkdirs(); //确保路径存在,没有的话就创建
for(File sub : src.listFiles()) { //递归 源的子孙级也要复制
copyDirDetail(sub, new File(dest,sub.getName())); //将src中的每一个拷贝到dest //父子目录创建
}
}
}
//文件拷贝
public static void copyFile(String srcPath,String destPath) throws FileNotFoundException,IOException {
File src = new File(srcPath);
File dest = new File(destPath);
copyFile(src,dest);
}
//文件拷贝重载
public static void copyFile(File src,File dest) throws FileNotFoundException,IOException {
if(!src.isFile()) {
throw new IOException("只能拷贝文件!");
}
//dest为已经存在的文件夹,不能建立与文件夹同名的文件
if(dest.isDirectory()){
throw new IOException(dest.getAbsolutePath() + "不能建立与文件夹同名的文件!");
}
InputStream is = new BufferedInputStream(new FileInputStream(src));
OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
byte[] bytes = new byte[1024];
int len = 0;
while(-1 != (len = is.read(bytes))) {
os.write(bytes, 0, len);
}
os.flush(); //强制刷出
//先打开的后关闭
os.close();
is.close();
}
/**
* 文件夹的删除
* @param file
*/
public static void deleteFile(File file) {
if (file.exists()) {
if (file.isFile()) { //如果是文件的话就直接删除
file.delete(); // 直接删除
}
else if (file.isDirectory()) {
File files[] = file.listFiles(); // 声明目录下所有的文件 files[];
for (int i = 0; i < files.length; i++) { // 遍历目录下所有的文件
deleteFile(files[i]); //递归删除
}
file.delete(); //递归完成之后把自己这个目录也要删掉
}
}
else {
System.out.println("所删除的文件不存在!" + '\n');
}
}
}
转换流(乱码问题)
转换流: 字节流转为字符流,处理乱码(编码集,解码集)
- 编码和解码的概念
编码 : 字符 -->编码字符集 ->二进制;
解码 : 二进制 ->解码字符集 -> 字符; - 乱码问题出现的原因:
- 编码与解码的字符集不统一
- 字节缺少,长度丢失
import java.io.UnsupportedEncodingException;
/**
* 测试乱码的问题:
* 1)编码与解码的字符集不统一
* 2)字节缺少,长度丢失
*/
public class ConvertProblemTest {
public static void main(String[] args) throws UnsupportedEncodingException {
test1();
test2();
}
/**
* 问题1 : 编码和解码的字符集不统一
*/
public static void test1() throws UnsupportedEncodingException {
// byte --> 解码
String str = "中国"; // gbk编码
// byte --> 编码
byte[] data = new byte[1024];
//不统一的字符集 -> 出现乱码
data = str.getBytes("gbk"); // utf8编码
System.out.println(new String(data)); // 编码不同出现乱码
byte[] data2 = new byte[100];
data2 = "中国".getBytes("utf-8"); // 使用utf-8编码
str = new String(data2, "utf-8"); // 使用utf-8解码
System.out.println(str);
}
/**
* 问题二: 字节缺少,长度丢失
*/
public static void test2(){
String str = "中国强";
byte[] data = str.getBytes();
//字节数不完整
System.out.println(new String(data,0,5)); //长度不足 也会乱码
}
}
效果:
解决乱码
- 就是在
FileInputStream
上面包装一层InputStreamReader
转换成字符流即可。
import java.io.*;
/**
* 解决乱码问题
* InputStreamReader
* OutputStreamWriter
*/
public class InputOrOutputStreamReaderOrWriterTest {
public static void main(String[] args) throws IOException {
copyFile("/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/in.txt",
"/home/zxzxin/Java_Maven/Java8/src/main/java/JavaPrimary/IO/io1/out.txt");
}
public static void copyFile(String srcPath,String destPath) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader( //这个就是将下面的 FileInputStream转换的流
new FileInputStream(
new File(srcPath)
)
,"GBK"
)
);
BufferedWriter wr = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(
new File(destPath)
)
,"GBK" //注意和上面的编码字符集要相同
)
);
String line = null;
while(null != (line = br.readLine())){
wr.write(line);
wr.newLine(); //可以在文件中使用"/r/n" 也可以使用这样的方法
}
wr.flush(); // 强制刷出
// 先打开的后关闭
wr.close();
br.close();
}
}