【java基础】--(3)javaIO详细阐释
1、总的4类
字符:Reader 和Writer
字节:InputStream和OutputStream
2、Reader六个子类BufferedReader,CharArrayReader,FilterReader,InputStreamReader,PipedReader,StringReader
2.1 BufferedReader为什么用它?
将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的
工作原理?
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
什么时候用?
建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)
示例1:包装InputStreamReader
InputStreamReader又包装System.in
将控制台输入,赋给字符串
BufferedReader buf = new BufferedReader( new InputStreamReader(System.in)); String str = null; System.out.println("请输入内容"); try{ str = buf.readLine(); }catch(IOException e){ e.printStackTrace(); } System.out.println("你输入的内容是:" + str);
子类:LineNumberReader
跟踪行号的缓冲字符输入流
工作原理?
把字符数组作为源的输入流的实现
什么时候用?
缓冲字符数组,读取每个字符的时候
示例1:读取字符数组中每个字符并输出
String strTmp = "abcdefghijklmnopqrstuvwxyz"; int intLen = strTmp.length(); char c[] = new char[intLen]; strTmp.getChars(0,intLen,c,0);
CharArrayReader input1 = new CharArrayReader(c); CharArrayReader input2 = new CharArrayReader(c,0,5);
int i; System.out.println("input1 is : "); while((i=input1.read())!=-1){ System.out.print((char)i); } System.out.println(); System.out.println("input2 is : "); while((i=input2.read())!=-1){ System.out.print((char)i); }
子类:PushbackReader
工作原理?
允许将字符推回到流的字符流
unread(char c) 回压一个字符; unread(char c[]) 回压数组 c 中全部字符
unread(char c[],offset,int n) 回压 c 中从 offset 开始的 n 个字符
为什么用它?
编译原理的一个重要的组成部分叫做词法分析器,就是我上面提到的scanner。对于词法分析程序来说,输入就是源代码,输出就是一个一个的Token(想不出来合适的词),通常词法分析器会一个字符一个字符读取,然后将将这些字符根据一定的规则组成token的序列。有些时候,scanner需要超前读下一个字符才能判断当前的token是否已经结束。例如,int abc=5;这样一个语句,词法分析器要读到=这个字符的时候才能确定abc是一个id,而不是"abc=",这样=已经从输入流中读出来了,但是=又不属于当前的Token,所以要把这个=退回去,这时就要用到pushback。
2.4InputStreamReader
是字节流通向字符流的桥梁
要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
子类:FileReader
工作原理?
用来读取字符文件的便捷类
示例1:读取字符文件并写到数组
路径分隔符:File.separator
String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); char[] ch=new char[100]; Reader read=new FileReader(f); int count=read.read(ch); read.close(); System.out.println("读入的长度为:"+count); System.out.println("内容为"+new String(ch,0,count));
工作原理?
传送的字符输入流。
什么时候用?
管道输入输出流类主要用于线程之间的通信,不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。
示例1:管道输入输出流类用于线程之间的通信(读管道中数据到字符数组,写到管道中)
两个线程
一个读一个写,都用到管道流,并返回管道流对象
主函数中得到输入输出对象
输出对象与输入对象打通管道 t1.connect(t2);
开启各自线程 s.start(); r.start();
PipedInputStream,PipedOutputStream管道输入输出流类主要用于线程之间的通信,不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。PipedReader,Pipedwriter字符输入输出流类和上面的类似import java.io.*;public class PipedStreamTest { public static void main(String[] args) { // TODO Auto-generated method stub Sender s=new Sender(); Reciever r=new Reciever(); PipedWriter t1=s.getWriter(); PipedReader t2=r.getReader(); try{ t1.connect(t2); } catch(Exception e) { e.printStackTrace(); } s.start(); r.start(); }}class Reciever extends Thread{ PipedReader in=new PipedReader(); public PipedReader getReader() { return in; } public void run() { char [] buf=new char[1024]; try{ int len=in.read(buf); System.out.println("the following messageid:"+'\n'+ new String(buf,0,len)); in.close(); } catch(Exception e) { e.printStackTrace(); } }}class Sender extends Thread{ private PipedWriter out=new PipedWriter(); public PipedWriter getWriter() { return out; } public void run() { String strInfo=new String("hello,how are you doing?"); try{ out.write(strInfo); out.close(); } catch(Exception e) { e.printStackTrace(); } }}
工作原理?
其源为一个字符串的字符流。文本信息当作内存中的字符一样来处理
什么时候用?
StringReader并不常用,因为通常情况下使用String更简单一些。但是在一些需要Reader作为参数的情况下,就需要将String读入到StringReader中来使用了
示例1:统计单词数
StreamTokenizer(reader);需要reader参数
文件未结束:streamTokenizer.nextToken() != StreamTokenizer.TT_EOF
读到单词:streamTokenizer.ttype == StreamTokenizer.TT_WORD
public void countWordsInAString() {StreamTokenizer streamTokenizer = null;String stringToBeParsed = "The quick brown fox jumped over the lazy dog";StringReader reader = new StringReader(stringToBeParsed);int wordCount = 0;try {streamTokenizer = new StreamTokenizer(reader);while (streamTokenizer.nextToken() != StreamTokenizer.TT_EOF) {if (streamTokenizer.ttype == StreamTokenizer.TT_WORD)wordCount++;}System.out.println("Number of words in file: " + wordCount);} catch (FileNotFoundException ex) {ex.printStackTrace();} catch (IOException ex) {ex.printStackTrace();}}3、Writer类
7个子类:BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter
简要说明下:
PrintWriter可以格式化输出;与PrintStream的区别就是可以自动刷新缓冲
FilterWriter没有子类了
其他的跟reader匹配着用,都差不多
3.1BufferedWriter工作原理?
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入
示例1:把数据写入文件
File file = new File(filepath); 02 //file.deleteOnExit(); 03 file.createNewFile(); 04 05 BufferedWriter write = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"UTF-8")); 06 write.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); 07 write.write("<locals>\n"); 08 09 10 write.write("\t</province>\n"); 11 System.out.println("===完成省份:"+pro.getValue()); 12 } 13 write.write("</locals>"); 14 System.out.println("全部完成。。。。。。。。"); 15 write.flush(); 16 write.close();
操作的都是字符数组
工作原理?
此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。可使用 toCharArray() 和 toString() 获取数据。
示例1:显示字符内容
//显示字符内容 array = charArrayWriter.toCharArray();
示例2:将字符数组内容存回文件
//将字符数组内容存回文件 CharArrayReader charArrayReader = new CharArrayReader(array); BufferedWriter bufWriter = new BufferedWriter( new FileWriter(file)); char[] tmp = new char[1]; while(charArrayReader.read(tmp)!=-1) { bufWriter.write(tmp); } charArrayReader.close(); bufWriter.flush(); bufWriter.close();
没啥用
3.4OutputStreamWriter工作原理?
是字符流通向字节流的桥梁
为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如:
示例1:字符串写入控制台
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
示例2:字符串写入文件
File f = new File("d:" + File.separator + "test.txt"); Writer out = null; out = new OutputStreamWriter(new FileOutputStream(f));// 字节流变为字符流 out.write("hello world"); // 使用字符流输出 out.close();3.5PipedWriter
见2.5PipedReader
3.6PrintWriter工作原理?
向文本输出流打印对象的格式化表示形式
是一种过滤流,也叫处理流。也就是能对字节流和字符流进行处理
可以对下面几种输出流格式化字符串输出
OutputStream
File
Writer
示例1:格式化
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
首先,创建一个与指定文件连接的FileWriter。实际上,我们通常会用BufferedWriter将起包装起来用以缓冲输出(......这里面的我省略了)。然后为了格式化把它转换成PrintWriter。
工作原理?
一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。 文本信息当作内存中的字符一样来处理
关闭 StringWriter 无效。此类中的方法在关闭该流后仍可被调用,而不会产生任何 IOException
StringWriter还有一个特点,那就是它能通过GetStringBuilder()方法来获取一个System.Text.StringBuilder对象:
示例1:获取一个System.Text.StringBuilder对象
StringWriter strWriter = new StringWriter();...StringBuilder sb = strWriter.GetStringBuilder();sb.Insert(0, "Hey!! ");Console.WriteLine("-> {0}", sb.ToString());sb.Remove(0, "Hey!! ".Length);
示例2:常规使用
StringWriter strWriter = new StringWriter();strWriter.WriteLine("Don't forget Mother's Day this year...");strWriter.Close();
4、InputStream
9个子类:AudioInputStream,ByteArrayInputStream,FileInputStream,FilterInputStream,InputStream,ObjectInputStream,PipedInputStream,SequenceInputStream,StringBufferInputStream
4.1AudioInputStream音频输入流是具有指定音频格式和长度的输入流。长度用示例帧表示,不用字节表示。
4.2ByteArrayInputStreamByteArrayInputStream
包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read
方法要提供的下一个字节。
关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用
什么时候使用?
网络传输中我们往往要传输很多变量,我们可以利用ByteArrayOutputStream把所有的变量收集到一起,然后一次性把数据发送出去
示例1:内存缓冲区的读写(直接用)
int a=0; 6 int b=1; 7 int c=2; 8 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 9 bout.write(a);10 bout.write(b);11 bout.write(c);12 byte[] buff = bout.toByteArray();13 for(int i=0; i<buff.length; i++)14 System.out.println(buff[i]);15 System.out.println("***********************");16 ByteArrayInputStream bin = new ByteArrayInputStream(buff);17 while((b=bin.read())!=-1) {18 System.out.println(b);
示例2:内存缓冲区的读写(配合DataOutputStream和DataInputStream)
11 byte[] buff = bout.toByteArray();
13 DataInputStream dis = new DataInputStream(bin);
ByteArrayOutputStream bout = new ByteArrayOutputStream(); 6 DataOutputStream dout = new DataOutputStream(bout); 7 String name = "xxy"; 8 int age = 84; 9 dout.writeUTF(name);10 dout.writeInt(age);11 byte[] buff = bout.toByteArray();12 ByteArrayInputStream bin = new ByteArrayInputStream(buff);13 DataInputStream dis = new DataInputStream(bin);14 String newName = dis.readUTF();15 int newAge = dis.readInt();16 System.out.println(newName+":"+newAge);4.3PipedInputStream类
管道事实上是一个队列
示例1:管道的输入与输出
import java.io.*;
public class PipedIO //程序运行后将sendFile文件的内容拷贝到receiverFile文件中
{
public static void main(String args[])
{
try
{
//构造读写的管道流对象
PipedInputStream pis=new PipedInputStream();
PipedOutputStream pos=new PipedOutputStream();
//实现关联
pos.connect(pis);
//构造两个线程,并且启动。
new Sender(pos,"c:\\text2.txt").start();
new Receiver(pis,"c:\\text3.txt").start();
}
catch(IOException e)
{
System.out.println("Pipe Error"+ e);
}
}
}
//线程发送
class Sender extends Thread
{
PipedOutputStream pos;
File file;
//构造方法
Sender(PipedOutputStream pos, String fileName)
{
this.pos=pos;
file=new File(fileName);
}
//线程运行方法
public void run()
{
try
{
//读文件内容
FileInputStream fs=new FileInputStream(file);
int data;
while((data=fs.read())!=-1)
{
//写入管道始端
pos.write(data);
}
pos.close();
}
catch(IOException e)
{
System.out.println("Sender Error" +e);
}
}
}
//线程读
class Receiver extends Thread
{
PipedInputStream pis;
File file;
//构造方法
Receiver(PipedInputStream pis, String fileName)
{
this.pis=pis;
file=new File(fileName);
}
//线程运行
public void run()
{
try
{
//写文件流对象
FileOutputStream fs=new FileOutputStream(file);
int data;
//从管道末端读
while((data=pis.read())!=-1)
{
//写入本地文件
fs.write(data);
}
pis.close();
}
catch(IOException e)
{
System.out.println("Receiver Error" +e);
}
}
}