什么是IO:
IO即数据的输入输出。将外设的数据读到内存中就是输入,将内存中数据写入到外设中就是输出。
IO流常见的基类:
这四个类的子类都是以父类名称作为子类名称的后缀,如InputStream的子类FileInputStream, Writer的子类:FileWriter.字节流的抽象基类:InputStream, OutputStream字符流的抽象基类:Reader, Writer
如果操作文字数据,优先考虑字符流。
例:拷贝文件
public class CopyTest {
public static void main(String[] args) {
FileReader fileReader = null;
FileWriter fileWriter = null;
try {
fileReader = new FileReader("from.txt");
fileWriter = new FileWriter("to.txt");
char[] arr = new char[5];//临时容器,用于缓存读到的字符
int len = 0;
while ((len=fileReader.read(arr))!=-1) {
fileWriter.write(arr,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if (fileWriter!=null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileReader!=null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
BufferedReader还有一个有用的子类:LineNumberReader
此类可以跟踪行号,定义了setLineNumber()和getLineNumber()方法
例:读取一个文件,并在每行前加上行号
public class LineNumberReaderDemo {
public static void main(String[] args) throws IOException{
//简化demo代码,暂不处理异常
FileReader fr = new FileReader("demo.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
while ((line = lnr.readLine())!=null) {
System.out.println(lnr.getLineNumber()+":"+line);
}
lnr.close();
}
}
字符流的缓冲区
缓冲区的出现提高了读写效率
对应的类:
BufferedWriter,BufferedReader.
缓冲区要结合流才可以使用,对流的功能进行了增强。可以把缓冲区想像成超市的小推车,必须要有货物在里面才起作用。缓冲区不调用资源,仅仅起到提高效率的作用。缓冲区的关闭就是关闭的流对象
仍然是拷贝文件的例子:
public class BufferDemo {
public static void main(String[] args) {
bufferReadAndWrite(new File("from.txt"),new File("to.txt"));
}
public static void bufferReadAndWrite(File from, File to) {
FileReader fileReader = null;
BufferedReader bufferedReader = null;
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
try {
fileReader = new FileReader(from);
bufferedReader = new BufferedReader(fileReader);
fileWriter = new FileWriter(to);
bufferedWriter = new BufferedWriter(fileWriter);
String string = null;
while ((string = bufferedReader.readLine()) != null) {
bufferedWriter.write(string);
bufferedWriter.newLine();
bufferedWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if (bufferedReader!=null) {
try {
bufferedReader.close();//同时关闭了流
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedWriter!=null) {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字节流:
基本操作和字符流相同,但它不仅可以操作字符,还可以操作其它媒体文件
例:拷贝一个.avi文件
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis =
new
FileInputStream(
"from.avi"
);
FileOutputStream fos =
new
FileOutputStream(
"to.avi"
);
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf))!=-1) {
fos.write(buf, 0, len);
fos.flush();
}
fos.close();
fis.close();
}
}
仍然是上面的例子,但是使用缓冲区:
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis =
new
FileInputStream(
"from.avi"
);
FileOutputStream fos =
new
FileOutputStream(
"to.avi"
);
BufferedInputStream bis =
new
BufferedInputStream(fis);
BufferedOutputStream bos =
new
BufferedOutputStream(fos);
int len = 0;
while ((len = bis.read())!=-1) {
bos.write(len);
}
bos.close();
bis.close();
}
}
转换流:InputStreamReader,OutputStreamWriter
InputStreamReader:
将字节流转换成字符流
OutputStreamWriter:将字符流转换成字节流
转换流还可以按指定编码表进行编码和解码
什么时候用转换流:
1,当目标或源对应的是字节流,但操作的却是文本数据,可以使用转换流作为桥梁
2,一旦操作的文本涉及指定
编码表进行编码和解码,必须使用转换流
例:将输入的字符串变成大写输出,若输入over则结束
public class SwitchStreamAndReader {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bos = new BufferedWriter(new OutputStreamWriter(System.out));
String a = null;
while ((a=br.readLine())!=null) {
if("over".equals(a)) break;
bos.write(a.toUpperCase());
bos.newLine();
bos.flush();
}
}
}
流的操作规律:
想要知道开发时用到哪些对象,只要通过四个“明确”就可以了
1,明确源和目的
源:InputStream Reader
目的: OutputStream Writer
2,明确数据是否是纯文本信息
源:是纯文本:Reader 否:InputStream
目的:是纯文本:Writer 否:OutputStream
3,明确具体的设备
源:硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的:硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4,是否需要其它功能
a,是否需要高效(缓冲区),是,就加上buffer
综合示例
public class ReaderAndWriter {
public static void main(String[] args) throws IOException {
// 复制一个文本文件
copyFile();
//读取键盘信息,并写入到文件
keyToFile();
//将一个文本文件输出到控制台
FileToConsole();
//读取键盘输入字符串显示到控制台
KeyToConsole();
//将中文字符串按UTF-8写入文件
chToFile();
}
private static void chToFile() throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("file5.txt"),"UTF-8"));
bufferedWriter.write("你好");
bufferedWriter.close();
}
private static void KeyToConsole() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
String str = null;
while ((str= bufferedReader.readLine())!=null) {
bufferedWriter.write(str);
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
private static void FileToConsole() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("file4.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
String str = null;
while ((str= bufferedReader.readLine())!=null) {
bufferedWriter.write(str);
bufferedWriter.flush();
bufferedWriter.newLine();
}
bufferedWriter.close();
bufferedReader.close();
}
private static void keyToFile() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File("file3.txt")));
String str = null;
while ((str= bufferedReader.readLine())!=null) {
bufferedWriter.write(str);
bufferedWriter.flush();
bufferedWriter.newLine();
}
bufferedWriter.close();
bufferedReader.close();
}
private static void copyFile() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(
"file1.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
"file2.txt"));
String str = null;
while ((str = bufferedReader.readLine()) != null) {
bufferedWriter.write(str);
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
}
}
打印流 PrintStream PrintWriter
为其他流添加功能,使它们能方便打印各种数据值的表式形式 。不会抛IO异常
public class PrintDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new FileWriter("out.txt"),true);
String str = null;
while ((str = br.readLine())!=null) {
if ("over".equals(str)) {
break;
}
pw.println(str);
}
}
}
合并数据:SequenceInputStream
例:将几个文本文件合并到一个文件
public class MergeFileDemo {
public static void main(String[] args) throws IOException {
Vector<FileInputStream> vector = new Vector<FileInputStream>();
vector.add(new FileInputStream("file1.txt"));
vector.add(new FileInputStream("file2.txt"));
vector.add(new FileInputStream("file3.txt"));
vector.add(new FileInputStream("file4.txt"));
Enumeration<FileInputStream> e = vector.elements();
SequenceInputStream sis = new SequenceInputStream(e);
BufferedReader bReader = new BufferedReader(new InputStreamReader(sis));
BufferedWriter bWriter = new BufferedWriter(new FileWriter("mergedFile.txt"));
String str = null;
while ((str=bReader.readLine())!=null) {
bWriter.write(str);
bWriter.newLine();
bWriter.flush();
}
bWriter.close();
bReader.close();
}
}
对象的序列化与反序列化:ObjectOutputStream ObjectInputStream
被操作的对象必须实现
Serializable接口,此接口用于给被序列化的类加入ID号,用于判断类和对象是否是同一版本
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectOutputStream oStream = new ObjectOutputStream(new FileOutputStream("person.object"));
oStream.writeObject(new Person("小张",18));
oStream.close();
ObjectInputStream isStream = new ObjectInputStream(new FileInputStream("person.object"));
Person person = (Person) isStream.readObject();
System.out.println(person.getName()+":"+person.getAge());
}
}
class Person implements Serializable{
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
管道流:
PipedInputStream
PipedOutputStream
可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入
PipedOutputStream
对象,并由其他线程从连接的
PipedInputStream
读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于
毁坏 状态。
public class PipeDemo {
public static void main(String[] args) throws IOException {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);//将管道连接起来
new Thread(new Input(in)).start();
new Thread(new Output(out)).start();
}
}
class Input implements Runnable{
private PipedInputStream inputStream;
public Input(PipedInputStream inputStream) {
this.inputStream = inputStream;
}
public void run() {
try {
byte[] buf = new byte[1024];
int len = inputStream.read(buf);
String str = new String(buf,0,len);
System.out.println("s="+str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Output implements Runnable{
private PipedOutputStream outputStream;
public Output(PipedOutputStream outputStream) {
this.outputStream = outputStream;
}
public void run() {
try {
outputStream.write("管道输出流".getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
}
操作内存的流:ByteArrayInputStream ByteArrayOutputStream
ByteArrayInputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪
read
方法要提供的下一个字节。
ByteArrayOutputStream 此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用
toByteArray()
和
toString()
获取数据。
这两个流关闭无效,在关闭后都可再次被调用(因为不涉及底层资源)而不会产生任何IO异常。
public class ByteArrayStreamDemo {
public static void main(String[] args) {
ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int a = 0;
while ((a=bis.read())!=-1) {
bos.write(a);
}
System.out.println(bos.toString());
}
}