I / O
定义:这是一种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input和输出output,即流向内存是输入流,流出内存的是输出流,输入即读取数据,输出即写出数据。
字节流(一切皆为字节)
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
直接上代码,基本就是读写,只不过操作文本文件的时候,由于含有中文所以使用字符流,其他情况都可以使用字节流。
// 一个文件的复制操作,思路就是去某个路径下读取,
// 然后去某个路径下写到硬盘中,就是一读一写
public class Review1 {
public static void main(String[] args) {
File file = new File("C:\\Koala.jpg");
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
FileInputStream fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(new File("D:\\"+file.getName()));
bos = new BufferedOutputStream(fos);
int len = 0;
while ((len = bis.read()) != -1) {
bos.write(len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
// 当然这边还可以判断下NPE
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符流
// 向文件中写入中文,FileWriter就是做这个的,FileOutputStream也可以做到
public class Review1 {
public static void main(String[] args) {
File file = new File("D:\\b.txt");
FileWriter fw = null;
try {
fw = new FileWriter(file, true);
fw.write("你好,你好");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class Review1 {
public static void main(String[] args) {
File file = new File("D:\\b.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
int len = 0;
byte[] b = new byte[1024];
while ((len = fis.read(b)) != -1) {
System.out.println(new String(b,0,len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
另外说一下,不知道你们乱不乱,反正我之前是有点绕,现在理清楚了。
fileInputStream.read()返回的是下一个字节的数据,而如果在read()中加上字节数组,则返回的一个文件总共字节的数量。
public class Review1 {
public static void main(String[] args) {
File file = new File("D:\\b.txt");
FileReader fr = null;
try {
fr = new FileReader(file);
int len = 0;
char[] b = new char[1024];// 注意读取字符时用的字符数组,而不是字节数组
while ((len = fr.read(b)) != -1) {
System.out.println(new String(b,0,len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这边顺便把缓冲流给提了,这个缓冲流也叫高效流,基本原理是在创建流对象时会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。所以可以给上面的操作套上一层盔甲,高效流。
public class Review1 {
public static void main(String[] args) {
File file = new File("D:\\file\\b.txt");
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(file);
br = new BufferedReader(fr);// 通过它的对象去读写数据,更快
int len = 0;
char[] b = new char[1024];
while ((len = br.read(b)) != -1) {
System.out.println(new String(b,0,len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
我说下字节流和字符流在读取中文文件的时候区别和相同之处,都尝试过了(以下都建立在文件的编码格式和文本编辑器的编码格式一致的情况下)。
// 这个可以正常读取文件,字节流+数组形式
FileInputStream fis = new FileInputStream(file);
int len = 0;
byte[] b = new byte[1024];
while ((len = fis.read(b)) != -1) {
System.out.println(new String(b,0,len));
}
// 这样只是读出来一个个字节,是数字的形式,单纯的字节流(不加数组)
FileInputStream fis = new FileInputStream(file);
int len = 0;
while ((len = fis.read()) != -1) {
System.out.println(len));
}
// 正常输出,字符流+数组
FileReader fr = new FileReader(file);
int len = 0;
char[] b = new char[1024];
while ((len = fr.read(b)) != -1) {
System.out.println(new String(b,0,len));
}
// 正常输出,单纯的字符流(不同于字节流,字符流返回的每个都是一个字符,
// 用char一转就读出来了)
FileReader fr = new FileReader(file);
int len = 0;
while ((len = fr.read()) != -1) {
System.out.print((char)len);
}
以上的这些情况都建立在要读取的文件的编码格式和文本编辑器的编码格式一致的情况下,那如果不一致呢?这时候就可以用到转换流
public class InputStream {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("D:/file/a.txt");
InputStreamReader isr = new InputStreamReader(fis,"gbk");
char[] chars = new char[1024];
int len=0;//有效字节个数
while((len=isr.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
fis.close();
}
}
这个转换流没什么难的,反正这些流都是某某的构造函数可以接收某某这个类的对象,比如转换流可以接收字节流,缓存流可以接收字节流,字符流可以接收文件类对象……你不用去记,理解字节字符,知道现在在操作什么格式的文件,是读还是要写,还是要边读边写,是否需要使用数组加快读取速度,格式的转换,读出来的每个是单个字符、字节还是整体的字节、字符的数量,写着写着就想起来了。
序列化流
序列化大致的意思是:
对象—>(序列化,对象转字节ObjectOutputStream)字节
字节—>(反序列化,字节重构对象ObjectInputStream)对象
public class Review1 {
public static void main(String[] args) {
File file = new File("D:\\file\\personSerializable.txt");
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
Person p1 = new Person("zhangsan", 18);
oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(p1);
ois = new ObjectInputStream(new FileInputStream(file));
Person p = (Person)ois.readObject();
System.out.println(p);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
try {
oos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
打印流
向指定的文件路径打印内容。原本是在控制台打印输出的,现在我们可以改变流对象的输出方向。
public static void main(String[] args) {
File file = new File("D:\\file\\b.txt");
PrintStream ps = null;
try {
ps = new PrintStream(file);
System.setOut(ps);
System.out.println("abc".toCharArray());
System.out.write(97);// a
System.out.append("123");
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
ps.close();
}
}
}
好的,以上就是我要说的大部分流对象,也就是常见的用法给敲了一下,给大家演示了一下,并不是很难,大家也可以尝试着玩一玩,还是比较有趣的一个知识点。