IO流用来处理设备之间的数据传输。
- 流按流向分为:输入流、输出流。
输入流、输出流相对于内存设备而言。将外设中的数据读取到内存:输入;将内存的数据写入到外设中:输出。 - 流按操作数据不同分为两种:字节流、字符流
字节流:通用流。
字符流:基于字节流。由来:字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的数字,在对该文字进行操作。
ASCII:英文编码表
GB2312/GBK:中文编码表
UTF-8:国际通用码表
如果对一台计算机使用GBK编码存储,那么另一台UTF-8的机器无法识别正确的文字,并显示乱码。因此,字符流可以指定编码方式来获取对应的文字。
二、I/O流常用基类
字符流
字节流的抽象基类:InputStream,OutputStream
字符流的抽象基类:Reader,Writer
P.S. 有着四个类派生出的子类名称都是以其父类名作为子类名的后缀。如InputStream的子类FileInputStream,如Reader的子类FileReader。
需求:将一些文字存储到硬盘一个文件中。
注意:如果要操作文字数据,建议优先考虑字符流。使用FileWriter。
import java.io.*;
class FileWriterDemo throws IOException {
public static void main(String[] args) {
//该文件会被创建到指定目录下。如果文件存在,则会被覆盖。
FileWriter fw = new FileWriter("demo.txt");
//将数据写入到临时存储缓冲区中
fw.write("abcde");
//刷新该流的缓冲,将临时存放的数据写入到目的地
//如果不写,则要等到缓冲区满才会写入目的地
fw.flush();
//关闭流,关闭资源,释放内存
fw.close();
}
}
I/O异常处理
import java.io.*
class FileWriterDemo2 {
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt");
fw.write("abcdefg");
} catch(IOException e) {
System.out.println("catch:" + e.toString());
} finally {
try {
if(fw != null)
fw.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}
对已有文件的数据续写
import java.io.*
class FileWriterDemo3 {
public static void main(String[] args) {
FileWriter fw = null;
try {
//true参数,代表不覆盖已有的文件,在已有文件的末尾处进行数据读写
fw = new FileWriter("demo.txt", true);
fw.write("hello\r\n"thanks); //记事本中按\r\n换行
} catch (IOException e) {
System.out.println("catch:" + e.toString());
} finally {
try {
if(fw != null)
fw.close();
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
}
需求:读取一个文件,将读取到的字符打印到控制台。
第一种读取方式:read()方法读取文本文件数据
import java.io.*
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
//创建一个文件读取流对象
//如果文件不存在,会抛出FileNotFountException
FileReader fr = new FileReader("demo.txt");
//调用读取流对象的read()方法
//read():一次读一个字符,而且会自动往下读。如果已到达流的末尾,则返回-1
int ch = 0;
while((ch = fr.read()) != -1) {
System.out.println((char)ch);
}
fr.close;
}
}
第二种读取方式:使用read(char[])读取文本文件数据
import java.io.*
public class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024];
int num = 0;
while((num = fr.read(buf)) != -1) {
System.out.println(new String(buf,0,num));
}
fr.close;
}
}
打印一个.java文件,并打印在控制台上
import java.io.*
class FileReaderTest throws IOException {
public static void main(String[] args) {
FileReader fr = new FileReader("DateDemo.java");
char[] buf = new char[1024];
int num = 0;
while((num = fr.read(buf)) != -1) {
System.out.println(new String(buf,0,num));
}
fr.close();
}
}
将C盘一个文本文件复制到D盘
复制的原理:将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1、在D盘创建一个文件,用于存储C盘文件的数据
2、定义读取流和C盘文件关联
3、通过不断读写完成数据存储
4、关闭资源
import java.io.*
class CopyText throws IOException {
public static void main(String[] args) {
FileWriter fw = null;
FileReader fr = null;
try {
fw = new FileWriter("D:\\SystemDemo_copy.txt");
fr = new FileReader("C:\\SystemDemo.java");
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf)) != -1) {
fw.write(buf,0,len);
}
} catch (IOException e) {
throw new RuntimeException("读写失败");
} finally {
if(fr != null) {
try {
fr.close();
} catch(IOException e) {
e.printStackTrace();
}
}
if(fw != null) {
try {
fw.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
}
字符流的缓冲区
缓冲区的出现提高了对数据的读写效率。
对应的类:BufferedWriter,BufferedReader
写入缓冲区
FileWriter fw = new FileWriter("buf.txt");
BufferedWriter bw = new BufferedWriter(fw);
for(int i=1; i<5; i++) {
bw.write("abcd" + x);
bw.newLine(); //跨平台的换行符
bw.flush(); //只要用到缓冲区,就要刷新
}
//关闭缓冲区,就是在关闭缓冲区中的流对象,故不需要写fw.close()
bw.close();
读取缓冲区
FileReader fr = new FileReader("buf.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
while((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
使用缓冲区复制文本文件
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader("xxx.java"));
bw = new BufferedWriter(new FileWriter("xxx_copy.txt"));
String line = null;
while((len = br.readLine()) != null) {
bw.write(line);
bw.newLine(); //readLine方法返回时,只返回回车符之前的数据内容,并不返回回车符,故要加上newLine()
bw.flush();
}
} catch (IOException e) {
throw new RuntimeException("读写失败");
} finally {
try {
if(br != null) {
br.close();
} catch(IOException e) {
throw new RuntimeException("读取关闭失败");
}
}
try {
if(bw != null) {
bw.close();
} catch(IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
写入换行使用BufferedWriter类中的newLine()方法。
读取一行数据使用BufferedReader类中的readLine()方法。
原理: 使用了读取缓冲区的read方法, 将读取到的字符进行缓冲并判断换行标记, 将标记前的缓冲数据变成字符串返回。
字节流
基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其它媒体文件。
InputStream,OutputStream
需求:操作图片数据
public static void writeFile throws IOException() {
FileOutputStream fos = new FileOutputStream("fos.txt");
//数据直接写到了目的地中
fos.write("abcde".getBytes());
//字节流不需要刷新
fos.close();
}
public static void writeFile throws IOException() {
FileInputStream fis = new FileInputStream("xxx.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1) {
System.out.println(new String(buf,0,len));
}
fis.close();
}
复制一个图片
思路:
1、用字节流读取对象和图片关联
2、用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
3、通过循环读写,完成数据的存储
4、关闭资源
class CopyPic {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("c:\\1.bmp");
fos = new FileOutputStream("c:\\2.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1) {
fos.write(buf,0,len);
}
} catch(IOException e) {
throw new RuntimeException("复制文件失败");
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e){
throw new RuntimeException("读取关闭失败");
}
try {
if(fos != null)
fos.close();
} catch (IOException e){
throw new RuntimeException("写入关闭失败");
}
}
}
}
演示MP3的复制,通过缓冲区
BufferedOutputStream
BufferedInputStream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by = bis.read()) != -1) {
bos.write(by);
}
bos.close();
bis.close();
转换流
InputStreamReader
字节流通向字符流的桥梁。解码。在构造时接受一个字节流。
读取转换流:
需求:当录入一行数据后,就将该行数据进行打印。如果录入的数据是over,那么停止录入。
//获取键盘录入对象
InputStream in = System.in;
//将字节流转换成字符流对象
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
BufferedReader br = new BufferedReader(isr);
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
System.out.println(line.toUpperCase());
}
br.close();
写入转换流:
OutputStreamWriter
字符通向字节的桥梁。编码。在构造时接收一个输出流。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush(); //务必写上
}
br.close();
需求:将键盘录入的数据写入到一个文件中。
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
需求:将一个文件的数据打印在控制台上。
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("xxx.java")));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
流操作的基本规律
通过两个明确来完成流对象的选择:
1、明确源和目的。
源:输入流 – InputStream Reader
目的:输出流 – OutputStream Writer
2、操作的数据是否是纯文本。
是:字符流
不是:字节流
3、当体系明确后,再明确使用哪个具体的对象。通过设备来进行区分。
源设备:内存、硬盘、键盘
目的设备:内存、硬盘、控制台
需求1:复制一个文本文件
源:InputStream / Reader
是否操作文本文件?是。选择Reader。
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘上的文件
Reader体系中可以操作文件的对象是FileReader
是否需要提高效率?是。加入Reader体系中的缓冲区BufferedReader
FileReader fr = new FileReader(“a.txt”);
BufferedReader br = new BufferedReader(fr);
目的:OutputStream / Writer
是否纯文本:是。选择Writer
设备:硬盘上的文件
Writer体系中可以操作文件的对象是FileWriter.
是否需要提高效率?是。加入Writer体系中的缓冲区BufferedWriter
FileWriter fw = new FileWriter(“b.txt”);
BufferedWriter bw = new BufferedWriter(fw);
File类
用来将文件或文件夹封装成对象的类,可以操作文件与文件夹的属性信息。File对象可以作为参数传递给流的构造函数。
流只能操作数据,如果要操作数据的文件对象,必须用到File对象。
File常用方法:
1、获取
文件名称getName()
文件路径getPath(),getAbsolutePath
文件大小length()
文件修改时间lastModified()
2、创建和删除
创建 boolean createNewFile()
删除 delete()
3、判断
是否可执行 canExcecute()
是否可读 canRead()
是否可写 canWrite()
是否存在 exists()
是否是文件 isFile()
是否是目录 isDirectory()
打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:PrintStream
构造函数可以接受的参数类型:
1、file对象。File
2、字符串路径。String
3、字节输出流。OutputStream
PrintStream永远不会抛出IOException
字符打印流:PrintWriter
构造函数可以接受的参数类型:
1、file对象。File
2、字符串路径。String
3、字节输出流。OutputStream
4、字符输出流。Writer
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("a.txt"), true)); //可以自动刷新
String line = null
while((line = br.readLine()) != null) {
if("over".equals(line))
break;
out.println(line.toUpperCase());
//out.flush();
}
out.close();
br.close();
序列流SequenceInputStream
对多个流进行合并。
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\4.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1) {
fos.write(buf,0,len);
}
fos.close();
sis.close();
切割流
public static void merge() {
ArrayList<FileInputStream> a1 = new ArrayList<FileInputStream>();
for(int x=1; x<=3; x++) {
}
}
public static void splitFile() throws IOException {
FileInputStream fis = new FileInputStream("c:\\1.bmp");
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];
int len = 0;
int count = 1;
while((len = fis.read(buf)) != -1) {
fos = new FileOutputStream("c:\\splitfiles\\"+(count++)".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}