先创建一个SD类,全篇都能用到:
public class SD{
// 定义文件分隔符
public static String s_f = System.getProperty("file.separator");
// 定义路径分隔符
public static String s_p = System.getProperty("path.separator");
// 定义行分隔符
public static String s_l = System.getProperty("line.separator");
// 定义项目路径
public static String d_w = System.getProperty("user.dir");
// 定义系统路径
public static String d_d = System.getProperty("user.home");
// 定义桌面路径
public static String d_h = d_h + s_f + "Desktop";
// 定义项目文件路径
public static String d_s = d_w + s_f + "src";
// 封装一个函数 用来获取文件的路径
public static String getPath(String ... args){
if(args.length == 0){
return d_d;
}
if(args.length == 1){
return args[0];
}
// 使用可变字符串用来拼接路径
StringBuffer sb = new StringBuffer();
// 多处使用 用于变量值的保存
int len = args.length;
for(int i= 0 ; i < len - 1 , i++){
sb.append(args[i]);
sb.append(s_f);
}
// 外部拼接最后一位
sb.append(args[i - 1]);
return new String(sb);
}
}
一.IO流
1.流的定义:程序操作数据类似于”管道输送水源” , 从源头到目标的一个不间断的持续过程 , 将此过程功能封装抽象定义出来的类称之为流(stream)
2.输入流与输出流:
输入流:将文件中的数据输入到程序中 , 形成程序数据
输出流:将程序中已有数据输出到文件中 , 形成持久化的数据
注意:
输入流 : Input < == > 读 : reader
输出流 : Output < == > 写 : writer
3.字节流与字符流:
字节流 : 以字节作为流的操作对象
字符流 : 以字符作为流的操作对象
注意:
1 ). 字符流可以高效的处理文本相关的数据 , 字节流可以处理任意文本数据.
2 ). 字符流有默认缓冲区 , 字节流不具有默认缓冲区(buffer).
二.文件字节输出流 - FileOutputStream
1.功能:将数据以字节的方式写入文件
字节:byte[] / int(ASCII码值)
2.书写步骤:
①.指定写入的文件存放的路径
②.指定写入的文件名
③.获取写入的信息(可以是字节数组:byte[] / int(ASCII码))
④.创建操作该文件的FileOutputStream类的对象
⑤.写入数据
⑥.关闭流(重点:必须关闭流)
3.代码举例:
首先在你的工作目录下创建io/io01/1.txt文件.
// 获取目标文件夹
String pathname = SD.getPath(SD.d_w , "io", "io01");
File path = new File(pathname);
// 写入时判断文件夹如果存在就创建它
if (!path.exists()) {
path.mkdirs();
}
// 获取目标文件
File file = new File(path, "1.txt");
// 需要写入的数据
String info = "①②③④⑤" + SD.s_l;
// 放入byte数组中
byte[] bs = info.getBytes();
// 创建FileOutputstream类以及相关操作
FileOutputStream output = null;
try {
// 第二个参数是代表可否续写而不是覆盖
output = new FileOutputStream(file , true);
// 写入方法
output.write(bs);
} catch (FileNotFoundException e) {
System.out.println("异常 - FileNotFoundException");
} catch (IOException e) {
System.out.println("异常 - IOException");
} finally {
try {
// 关闭流
if (output != null) {
output.close();
}
} catch (IOException e) {
System.out.println("异常 - IOException");
}
}
// 提示执行完毕
System.out.println("执行完毕!!");
三.文本字节输出流 - FileInputStream
1.功能:以字节来操作单位 读取文本中的数据
2.书写步骤:
①.获取对应的目标文件
②.创建文件对应的FileInputStream类的对象
③.通过流对象读取文件内容
④.使用读取到的内容(打印 / 展示 / 再次写入)
⑤.关闭流
3.代码举例:
1).读取数字/英文
首先在你的工作目录下创建io/io02/100.txt文件.
// 获取目标文件
String child = SD.getPath("io" , "io02" , "100.txt");
File file = new File(SD.d_w , child);
// 创建文件对应的FileInputStream类
FileInputStream input = null;
try {
// 创建流的对象的时候可能会出现FileNotFoundException
input = new FileInputStream(file);
// 使用流读取文件时可能会出现IOException
int res = 0;
/*
* 使用read() 读取文件
* 1).一次只会读取一个文件
* 2).返回的是读取到的字节对应的ASCII码值
* 3).读取的文件 最后没有数据时会返回-1
*/
// input.read() 既是判断条件 又是运算结果
// 所以将此操作上移到循环作为判断条件 操作用()嵌套在循环条件
// 使用这种方法可以一个字节读取 同时将一个字节输出到控制台上
while ((res = input.read()) != -1) {
// 直接输出汉字的话会出现乱码
System.out.printf("%c" , res);
}
} catch (FileNotFoundException e) {
System.out.println("异常 - FileNotFoundException");
} catch (IOException e) {
System.out.println("异常 - IOException");
} finally {
try {
// 为了避免出现空指针异常(流创建失败 流就不会存在)
if (input != null) {
input.close();
}
} catch (IOException e) {
System.out.println("异常 - IOException");
}
}
// 提示程序执行完毕
System.out.println("执行完毕!!");
2).读取中英文共存
首先在工作目录下创建目标文件 然后再编写代码:
// 获取目标文件
String child = SD.getPath("io" , "io02" , "100.txt");
File file = new File(SD.d_w , child);
// 创建文件对应的FileInputStream类
FileInputStream input = null;
try {
// 创建流的对象的时候可能会出现FileNotFoundException
input = new FileInputStream(file);
// 使用流读取文件时可能会出现IOException
int len = 0;
// input.read() 既是判断条件 又是运算结果
// 后面的[]是每次读取的字节
// 这次给的是文件的长度 如果文件过大可能会崩
// 所以[]中的长度应该给适当的距离
byte[] res = new byte[(int)file.length()];
while ((len = input.read()) != -1) {
// 直接输出汉字的话会出现乱码
System.out.println(new String(res));
}
} catch (FileNotFoundException e) {
System.out.println("异常 - FileNotFoundException");
} catch (IOException e) {
System.out.println("异常 - IOException");
} finally {
try {
// 为了避免出现空指针异常(流创建失败 流就不会存在)
if (input != null) {
input.close();
}
} catch (IOException e) {
System.out.println("异常 - IOException");
}
}
// 提示程序执行完毕
System.out.println("执行完毕!!");
四.字节流的边读边写(复制文本)
1.书写步骤:
①.获取读取的目标文件(要复制的文本)
②.确定要写入的目标文件(复制到的目标文本)
③.创建对应文件对应的输入流 和 输出流
④.读取内容 并 写入内容
⑤.关闭流
2.代码举例:
1).文本文件的复制
首先在工作目录下创建目标文件 然后再编写代码:
// 获取要读取目标文件
String sPath= SD.getPath(SD.d_w , "io" , "io02" , "100.txt");
File source = new File(sPath);
// 获取要写入的目标文件
String tPath = SD.getPath(SD.d_w , "io" , "io02" , "101.txt");
File target = new File(tPath);
// 获取目标文件对应的输入 和 输出流
FileOutputStream out = null;
FileInputStream in = null;
try {
// 读取目标文件
in = new FileInputStream(source);
// 写入目标文件
out = new FileOutputStream(target);
// 复制文件
int res = 0;
while ((res = in.read()) != -1) {
// 写入文件的方法write()
out.write(res);
}
} catch (FileNotFoundException e) {
System.out.println("异常 - FileNotFoundException");
} catch (IOException e) {
System.out.println("异常 - IOException");
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
System.out.println("异常 - IOException");
}
}
// 提示程序执行完毕
System.out.println("执行完毕!!");
2).非文本文件的复制
首先在工作目录下创建目标文件 然后再编写代码:
File source = new File(SD.d_d , "001.png");
File target = new File(SD.d_d , "002.png");
// 将所有的异常上抛给main函数处理
FileInputStream in = new FileInputStream(source);
FileOutputStream out = new FileOutputStream(target);
// 读写操作 -- 复制操作
int len = 0;
byte[] res = new byte[1];
while ((len = in.read(res)) != -1) {
// 按byte[]数组进行数据写入 从0开始 写入了len长度
out.write(res , 0 , len);
}
in.close();
out.close();
// 删除源文件
source.delete();
六.文件字符流 - 读(Reader) / 写(Writer)
1.定义:以字符为单位操作文本文件.
2.字符的好处(相比于字节):
①.文本文件专属操作流 可以更高效率的操作文本
②.拥有默认缓冲区 所以字符流不操作文件本身 操作的是缓冲区
③.以字符为操作单位 无需考虑不同字符所占字节数
3.对应的流的方法:
Reader <==> FileReader
Writer <==> FileWriter
4.代码举例:
public static void main(String[] args) {
//writeSomething();
readSomething();
}
// 写入文本文件
private static void writeSomething() {
String path = SD.getPath(SD.d_w , "io" , "io03");
File file = new File(path , "a.txt");
FileWriter writer = null;
try {
// 续写
writer = new FileWriter(file , true);
char[] info = {'1' , 'A' , '一' , '①'};
// 从info数组的索引1开始 截取3长度写入到文件中
writer.write(info , 1 , 2);
// 书写一次 清一次缓冲区
writer.flush();
writer.write("��"); // 这里写的是4个字节 网页读取不了
writer.flush();
writer.write("��");
writer.flush();
writer.write(SD.s_l);
// 最后一次清缓冲区操作可以交给close()
} catch (IOException e) {
System.out.println("异常 - IOException");
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
System.out.println("异常 - IOException");
}
}
System.out.println("写入完成!!");
}
// 读取文本文件
private static void readSomething() {
String path = SD.getPath(SD.d_w , "io" , "io03");
File file = new File(path , "a.txt");
FileReader reader = null;
try {
reader = new FileReader(file);
int len = 0;
char[] info = new char[1];
while ((len = reader.read(info)) != -1) {
// 延时打印
long time = System.currentTimeMillis();
while (System.currentTimeMillis() - time < 60) {}
// 告诉打印时可能解析错误
// 原因: "��""��"占4个字节 char占两个字节 需两次读取 才可以解析为完整字符
// 且系统对应字符流已经被处理(char一次读取不完的字符会被增加标识)
System.out.print(new String(info , 0 , len));
}
} catch (FileNotFoundException e) {
System.out.println("异常 - FileNotFoundException");
} catch (IOException e) {
System.out.println("异常 - IOException");
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
System.out.println("异常 - IOException");
}
}
System.out.println("读取完成!!");
}