IO流概述:
处理设备间数据传输问题
IO流分类:
1、按流向(一定要站在Java程序这边看问题)
–>输入流
–>输出流
2、按类型
–>字节流(图片,视频,音频,等多媒体文件)
–>字符流(.txt结尾的文本文件)
1、IO【字节流】抽象类和具体类的关系图:适合任意类型的文件读写
2、IO【字符流】抽象类和具体类的关系图:只适合文本类型的文件读写
1、字节流写数据:
OutputStream:此抽象类是表示输出字节流的所有类的超类
FileOutputStream:文件输出流是用于将数据写入 File
构造方法:
FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。
2、字节流写数据的步骤:
—A:创建字节输出流对象
—B:调用写数据的方法
—C:释放资源
首先我写一个Demo让大家看看:
编写使用FileOutputStream写数据的案例
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
FileOutputStream fos = new FileOutputStream("a.txt");
/*
* 创建字节输出流对象做了这样的三件事情:
* A:调用系统功能创建了文件
* B:创建字节输出流对象
* C:让fos这个对象指向a.txt这个文件
*/
//write(int b)
fos.write(65);
fos.write(66);
//最后我们还要做一个事情
//close() 关闭此文件输出流并释放与此流有关的所有系统资源。
fos.close();
}
}
1、构造方法:
public void write(int b):一次写一个字节
public void write(byte[] b):一次写一个字节数组
String类中的getByes(),返回值为byte[]数组
public void write(byte[] b,int off,int len):一次写一个字节数组的一部分
2、字节流写数据的步骤:
—A:创建字节输出流对象
—B:调用写数据的方法
—C:释放资源
public class FileOutputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
//FileOutputStream(String name)
FileOutputStream fos = new FileOutputStream("b.txt");
//new File(name)
// FileOutputStream fos = new FileOutputStream(new File("b.txt"));
//FileOutputStream(File file)
// File file = new File("b.txt");
// FileOutputStream fos = new FileOutputStream(file);
// FileOutputStream fos = new FileOutputStream(new File("b.txt"));
//public void write(int b):一次写一个字节
// fos.write(65);
//public void write(byte[] b):一次写一个字节数组
// byte[] bys = {65,66,67,68,69};
// fos.write(bys);
//需求:我如果是一个字符串的数据,能写吗?
//String -- byte[]
//String类中有一个方法:public byte[] getBytes()
// byte[] bys = "ABCDE".getBytes();
// fos.write(bys);
// fos.write("ABCDE".getBytes());
//public void write(byte[] b,int off,int len):一次写一个字节数组的一部分
fos.write("ABCDE".getBytes(),0,3);
//释放资源
fos.close();
}
}
1、如何实现数据的换行?
2、如何实现数据的追加写入?
例如:FileOutputStream fos = new FileOutputStream("c.txt",true);
public class FileOutputStreamDemo3 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
//FileOutputStream fos = new FileOutputStream("c.txt");
//FileOutputStream(String name, boolean append)
//如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处
FileOutputStream fos = new FileOutputStream("c.txt",true);
//调用写数据的方法
for(int x=0; x<10; x++) {
fos.write("hello".getBytes());
//加入换行符号
fos.write("\r\n".getBytes());
}
//释放资源
fos.close();
}
}
public class FileOutputStreamDemo4 {
public static void main(String[] args) {
// FileOutputStream fos = new FileOutputStream("d.txt");
// fos.write("hello".getBytes());
// fos.close();
//分开做异常处理
// FileOutputStream fos = null;
// try {
// fos = new FileOutputStream("d.txt");
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// }
// try {
// fos.write("hello".getBytes());
// } catch (IOException e) {
// e.printStackTrace();
// }
// try {
// fos.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
//放在一起做异常处理
// try{
// FileOutputStream fos = new FileOutputStream("d.txt");
// fos.write("hello".getBytes());
// fos.close();
// }catch(IOException e) {
// e.printStackTrace();
// }
//这种方式代码虽然简洁了,但是释放资源的动作可能未执行到
//try...catch...finally
FileOutputStream fos = null;
try{
//FileOutputStream fos = new FileOutputStream("d.txt");
// fos = new FileOutputStream("z:\\d.txt");
fos = new FileOutputStream("d.txt");
fos.write("hello".getBytes());
}catch(IOException e) {
e.printStackTrace();
}finally {
if(fos!=null) {
//释放资源
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1、一次读一个字节
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis = new FileInputStream("a.txt");
/*
//调用读数据的方法
//public int read():读取一个字节的数据,如果已到达文件末尾,则返回 -1。
int by = fis.read();
System.out.println(by);
System.out.println((char)by);
//再来读取一次
by = fis.read();
System.out.println(by);
System.out.println((char)by);
//发现读数据的代码的重复度很高,想用循环改进
//但是我们不知道循环的结束条件
//再来读取两次
by = fis.read();
System.out.println(by);
by = fis.read();
System.out.println(by);
*/
// int by = fis.read();
// while(by != -1) {
// System.out.print((char)by);
// by = fis.read();
// }
//改进版本
int by;
//fis.read()
//by=fis.read()
//by != -1
while((by=fis.read())!=-1) {
System.out.print((char)by);
}
//释放资源
fis.close();
}
}
2、一次读取一个字节数组
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis = new FileInputStream("b.txt");
/*
//调用读数据的方法
//定义一个数组
byte[] bys = new byte[5];
//第一次读取
int len = fis.read(bys);
System.out.println(len);
//byte[] -- String
//String(byte[] bytes)
//String(byte[] bytes, int offset, int length)
System.out.println(new String(bys));
//第二次读取
len = fis.read(bys);
System.out.println(len);
System.out.println(new String(bys));
//第三次读取
len = fis.read(bys);
System.out.println(len);
// System.out.println(new String(bys));
System.out.println(new String(bys,0,len));
//第四次读取
len = fis.read(bys);
System.out.println(len);
//第五次读取
len = fis.read(bys);
System.out.println(len);
*/
/*
* hello\r\n
* world\r\n
*
* hello
* \r\nwor
* ld\r\nr
*/
/*
byte[] bys = new byte[5];
int len = fis.read(bys);
while(len != -1) {
System.out.print(new String(bys,0,len));
len = fis.read(bys);
}
*/
//最终版代码
byte[] bys = new byte[1024]; //1024或者1024的整数倍
//1G = 1024MB
//1MB = 1024KB
//...
int len;
while((len=fis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
//释放资源
fis.close();
}
}
/*
* 把d:\\mn.jpg内容复制到当前项目目录下的mn.jpg中
*
* 数据源:
* d:\\mn.jpg---读数据---FileInputStream
* 目的地:
* mn.jpg---写数据---FileOutputStream
*/
public class CopyJpgTest {
public static void main(String[] args) throws IOException {
//封装数据源
FileInputStream fis = new FileInputStream("d:\\mn.jpg");
//封装目的地
FileOutputStream fos = new FileOutputStream("mn.jpg");
//读写数据
//方式1:一次读取一个字节,一次写一个字节(自己练习)
//方式2:一次读取一个字节数组,一次写一个字节数组的一部分
byte[] bys = new byte[1024];
int len;
while((len=fis.read(bys))!=-1) {
fos.write(bys,0,len);
}
//释放资源
fos.close();
fis.close();
}
}
字节缓冲区流:
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
// BufferedOutputStream(OutputStream out)
// FileOutputStream fos = new FileOutputStream("a.txt");
// BufferedOutputStream bos = new BufferedOutputStream(fos);
// 上面的两句等价于下面的这一句
// BufferedOutputStream bos = new BufferedOutputStream(new
// FileOutputStream("a.txt"));
// bos.write("hello".getBytes());
// bos.close();
// BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
//方式1:一次读取一个字节
// int by;
// while((by=bis.read())!=-1) {
// System.out.print((char)by);
// }
//方式2:一次读取一个字节数组
byte[] bys = new byte[1024];
int len;
while((len=bis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
bis.close();
}
}
1、把d:\复制图片.avi复制到当前项目目录下的copy.avi中
2、四种方式比较复制效率
public class CopyAviTest {
public static void main(String[] args) throws IOException {
//记录开始时间
long start = System.currentTimeMillis();
// method1();
// method2();
// method3();
method4();
//记录结束时间
long end = System.currentTimeMillis();
System.out.println("共耗时:"+(end-start)+"毫秒");
}
//缓冲字节流一次读写一个字节数组
private static void method4() throws IOException {
//封装数据源
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制图片.avi"));
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
byte[] bys = new byte[1024];
int len;
while((len=bis.read(bys))!=-1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
//缓冲字节流一次读写一个字节
private static void method3() throws IOException {
//封装数据源
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制图片.avi"));
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.avi"));
int by;
while((by=bis.read())!=-1) {
bos.write(by);
}
bos.close();
bis.close();
}
//基本字节流一次读写一个字节数组
private static void method2() throws IOException {
//封装数据源
FileInputStream fis = new FileInputStream("d:\\复制图片.avi");
//封装目的地
FileOutputStream fos = new FileOutputStream("copy.avi");
byte[] bys = new byte[1024];
int len;
while((len=fis.read(bys))!=-1) {
fos.write(bys,0,len);
}
fos.close();
fis.close();
}
//基本字节流一次读写一个字节
private static void method1() throws IOException {
//封装数据源
FileInputStream fis = new FileInputStream("d:\\复制图片.avi");
//封装目的地
FileOutputStream fos = new FileOutputStream("copy.avi");
int by;
while((by=fis.read())!=-1) {
fos.write(by);
}
fos.close();
fis.close();
}
}
==>转换流出现的原因【理解】
原因:
字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。
文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
汉字存储的规则:
左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分 情况下是负数。
如: String s1 = "hello";
//[104, 101, 108, 108, 111]
String s2 = "你好";
//[-60, -29, -70, -61]
===》OutputStreamWriter写数据方法
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
//public void write(int c):写一个字符
// osw.write(97);
// osw.write('a');
//写完数据后,没有发现数据,为什么呢?
//1字符=2字节
//文件中的数据存储的基本单位是字节
//public void write(char[] cbuf):写一个字符数组
// char[] chs = {'a','b','c','d','e'};
// osw.write(chs);
//public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
// char[] chs = {'a','b','c','d','e'};
// osw.write(chs, 1, 3);
//public void write(String str):写一个字符串
// osw.write("hello");
//public void write(String str,int off,int len):写一个字符串的一部分
osw.write("hello", 0, 3);
// //void flush():刷新该流的缓冲
// osw.flush();
//
// //释放资源
osw.close(); //关闭此流,但要先刷新它
}
}
===》InputStreamReader读数据方法
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
//创建字符输入流对象
// InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("OutputStreamWriterDemo.java"));
//public int read():一次读取一个字符
// int ch;
// while((ch=isr.read())!=-1) {
// System.out.print((char)ch);
// }
//public int read(char[] cbuf):一次读取一个字符数组
char[] chs = new char[1024];
int len;
while((len=isr.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
//释放资源
isr.close();
}
}
把当前项目目录下的StringDemo.java内容复制到当前项目目录下的Copy.java中(改进版)
转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。
OutputStreamWriter
InputStreamReader
StringDemo.java---读数据---字符流---InputStreamReader---FileReader
Copy.java---写数据---字符流---OutputStreamWriter---FileWriter
public class CopyJavaTest2 {
public static void main(String[] args) throws IOException {
//封装数据源
FileReader fr = new FileReader("StringDemo.java");
//封装目的地
FileWriter fw = new FileWriter("Copy.java");
//读写数据
//一次读写一个字符
// int ch;
// while((ch=fr.read())!=-1) {
// fw.write(ch);
// }
//一次读写一个字符数组
char[] chs = new char[1024];
int len;
while((len=fr.read(chs))!=-1) {
fw.write(chs, 0, len);
}
//释放资源
fw.close();
fr.close();
}
}
===》字符缓冲区流:
1、BufferedWriter:
BufferedWriter(Writer out)
2、BufferedReader:
BufferedReader(Reader in)
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
// //创建字符缓冲输出流对象
// BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
// //调用写数据的方法
// bw.write("hello");
// //释放资源
// bw.close();
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("BufferedStreamDemo.java"));
//方式1:一次读取一个字符
// int ch;
// while((ch=br.read())!=-1) {
// System.out.print((char)ch);
// }
//方式2:一次读取一个字符数组
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
//释放资源
br.close();
}
}
1、BufferedWriter特殊功能:
void newLine():写入一个行分隔符,这个行分隔符是由系统决定的
2、BufferedReader特殊功能:
String readLine():包含该行内容的字符串,不包含任何行终止符,
如果已到达流末尾,则返回 null
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
// //创建字符缓冲输出流对象
// BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
//
// //写数据
// for(int x=0; x<3; x++) {
// bw.write("hello");
bw.write("\r\n");
// bw.newLine();
// bw.flush();
// }
//
// //释放资源
// bw.close();
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
// //读取一次
// String line = br.readLine();
// System.out.println(line);
// //在读取一次
// line = br.readLine();
// System.out.println(line);
// line = br.readLine();
// System.out.println(line);
// //多读取两次
// line = br.readLine();
// System.out.println(line);
// line = br.readLine();
// System.out.println(line);
//最终版代码
String line;
while((line=br.readLine())!=null) {
System.out.println(line);
}
//释放资源
br.close();
}
}
每一个学生数据作为文件中的一行数据
===>定义一个学生类。
学生:
学号,姓名,年龄,所在城市
it001,张曼玉,35,北京
it002,王祖贤,33,上海
it003,林青霞,30,西安
===>分析步骤:
A:创建集合对象
B:创建学生对象
C:把学生对象添加到集合中
D:创建字符缓冲输出流对象
E:遍历集合,得到每一个学生对象,然后把该对象的数据拼接成一个指定格式的字符串写到文本文件
F:释放资源
public class ArrayListToFileTest {
public static void main(String[] args) throws IOException {
// 创建集合对象
ArrayList<Student> array = new ArrayList<Student>();
// 创建学生对象
Student s1 = new Student("it001", "张曼玉", 35, "北京");
Student s2 = new Student("it002", "王祖贤", 33, "上海");
Student s3 = new Student("it003", "林青霞", 30, "西安");
// 把学生对象添加到集合中
array.add(s1);
array.add(s2);
array.add(s3);
// 创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("students.txt"));
// 遍历集合,得到每一个学生对象,然后把该对象的数据拼接成一个指定格式的字符串写到文本文件
for (Student s : array) {
// it001,张曼玉,35,北京
StringBuilder sb = new StringBuilder();
sb.append(s.getSid()).append(",").append(s.getName()).append(",").append(s.getAge()).append(",")
.append(s.getCity());
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
}
}
===>学习IO流这块的话,最好是有一套完整的IO流体系框架图,再配上一些案例分析进行大量练习,一定要把所学的知识运用到实践上,这样才能有效地提升自己的技术,我写这篇博文是为了分享给大家,希望大家可以一步一步的构建自己的知识体系,祝大家可以拿到满意的offer!!!