IO基础到加强
1、文件的逻辑结构
流式文件
记录式文件
2、文件的存取方法
顺序存取
随机存取
3、文件的使用
操作接口
应用程序接口
4、流的定义和作用
流的定义、方向性和读/写操作
流采用缓冲区技术
流的作用:简单的说就是控制文件的输入和输出
5、流的存在
通过这个图,就可以很好的理解输入流和输出流,它们的命名是以程序为参展点,写进程序来,就是要用输入流,写出程序(写到文件中)就是要用输出流。
主要分为两大类:字节流和字符流
(1)InputStream 抽象字节输入流类
public abstract class InputStream extends Object implements Closeable { public abstract int read() throws IOException; //返回读取的一个字节,抽象方法 public int read(byte[] b) throws IOException //从输入流中读取若干字节到指定缓冲区,返回实际读取的字节数 public void close() throws IOException {} //关闭输入流,空方法 }
public class FileInputStream extends InputStream { public FileInputStream(String name) throws FileNotFoundException public FileInputStream(File file) throws FileNotFoundException }
b、数据字节输入流 DataInputStream类
public class DataInputStream extends FilterInputStream implements DataInput { public DataInputStream(InputStream in) //构造方法 public final short readShort() throws IOException public final byte readByte() throws IOException public final int readInt() throws IOException //读取整型 public final long readLong() throws IOException public final float readFloat() throws IOException public final double readDouble() throws IOException public final char readChar() throws IOException //读取字符 public final boolean readBoolean() throws IOException }c、对象字节输入流 ObjectInputStream类
public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants { public ObjectInputStream(InputStream in) throws IOException //构造方法 public final Object readObject() throws IOException, ClassNotFoundException //读取一个对象 }
(2)OuputStream 抽象字节输出流类
public abstract class OutputStream extends Object implements Closeable, Flushable { public abstract void write(int b) throws IOException; //写入一个字节,抽象方法 public void write(byte[] b) throws IOException //将缓冲区中的若干字节写入输出流 public void flush() throws IOException {} //立即传输 public void close() throws IOException {} //关闭输出流,空方法 }
public class FileOutputStream extends OutputStream { public FileOutputStream(String name) throws FileNotFoundException public FileOutputStream(File file) throws FileNotFoundException public FileOutputStream(String name, boolean append) throws FileNotFoundException }
b、数据字节输出流 DataOutputStream类
public class DataOutputStream extends FilterOutputStream implements DataOutput { public DataOutputStream(OutputStream out) //构造方法 public final void writeByte(int v) throws IOException public final void writeShort(int v) throws IOException public final void writeInt(int v) throws IOException //写入一个整型 public final void writeLong(long v) throws IOException public final void writeFloat(float v) throws IOException public final void writeDouble(double v) throws IOException public final void writeChar(int v) throws IOException //写入一个字符 public final void writeBoolean(boolean v) throws IOException public final void writeChars(String s) throws IOException //写入一个字符串 public final int size() //返回实际写入的字节数 }c、对象字节输出流 ObjectOutputStream类
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants { public ObjectOutputStream(OutputStream out) throws IOException //构造方法 public final void writeObject(Object obj) throws IOException //写入一个对象 }
(3)管道字节流
a、PipedInputStream类
b、PipedOutputStream类
PipedInputStream in = new PipedInputStream(); try { PipedOutputStream out= new PipedOutputStream(in); } catch(IOException ioe) {}用这个做发牌器就很方便:
(1)抽象字符流
a、Reader类
public abstract class Reader extends Object implements Readable, Closeable { public int read() throws IOException public int read(char cbuf[]) throws IOException abstract public int read(char cbuf[], int off, int len) throws IOException; abstract public void close() throws IOException; }b、Writer类
public abstract class Writer implements Appendable, Closeable, Flushable { public void write(int c) throws IOException public void write(char[] cbuf) throws IOException public void write(String str) throws IOException //将字符串写入输出流 public Writer append(CharSequence csq) throws IOException public Writer append(char c) throws IOException public abstract void flush() throws IOException //将缓冲区内容写入输出流 public abstract void close() throws IOException }(2)文件字符流
a、FileReader类
public class FileReader extends InputStreamReader { public FileReader(String fileName) throws FileNotFoundException //构造方法 public FileReader(File file) throws FileNotFoundException }b、 FileWriter类
public class FileWriter extends OutputStreamWriter { public FileWriter(String fileName) throws IOException //构造方法 public FileWriter(String fileName, boolean append) throws IOException public FileWriter(File file) throws IOException public FileWriter(File file, boolean append) throws IOException }
a、BufferedReader类
public class BufferedReader extends Reader { public BufferedReader(Reader in) //构造方法 public String readLine() throws IOException //读取一行字符串,输入流结束时返回null }
b、BufferedWriter类
public class BufferedWriter extends Writer { public BufferedWriter(Writer out) //构造方法 public BufferedWriter(Writer out, int sz) //sz指定字符缓冲区长度 public void newLine() throws IOException //写入一个换行符 }
(1)文件操作类
a、File类的构造方法
public class File extends Object implements Serializable, Comparable<File> { public File(String pathname) public File(String parent, String child) public File(File parent, String child) }例如:
File file = new File("myfile.txt"); File dir = new File(".",""); //创建一个目录文件对象,表示当前目录 File dir = new File("C:","");b、File类提供的方法
public String getName() //返回文件名,不包含路径名 public String getPath() //返回相对路径名,包含文件名 public String getAbsolutePath() //返回绝对路径名,包含文件名 public String getParent() //返回父文件对象的路径名 public File getParentFile() //返回父文件对象
(2)文件过滤器接口
a、FileFilter和FilenameFilter接口
public interface FileFilter { public boolean accept(File pathname) } public interface FilenameFilter { public boolean accept(File dir, String name) }b、获得文件列表时使用过滤器
public String[] list(FilenameFilter filter) //过滤显示文件清单 public File[] listFiles(FilenameFilter filter) public File[] listFiles(FileFilter filter)(3)文件对话框组件
a、JFileChooser类
public class JFileChooser extends JComponent implements Accessible { public static final int APPROVE_OPTION = 0; //单击“打开”或“保存”按钮 public static final int CANCEL_OPTION = 1; //单击“撤消”按钮 public static final int ERROR_OPTION = -1; //出错 public JFileChooser() public JFileChooser(String currentDirectoryPath) //初始路径 public JFileChooser(File currentDirectory) public void setFileFilter(FileFilter filter) //设置文件过滤器 public int showOpenDialog(Component parent) throws HeadlessException //显示打开文件对话框 public int showSaveDialog(Component parent) throws HeadlessException //显示保存文件对话框 public File getSelectedFile() //返回选中文件 }b、JFileChooser的文件过滤器
public abstract class FileFilter extends Object { public abstract boolean accept(File f) //过滤操作,f指定待过滤文件 public abstract String getDescription() //文件类型描述字符串 }
import java.io.File; import java.io.FilenameFilter; import javax.swing.JFileChooser; import javax.swing.JFrame; public class DirFilter implements FilenameFilter{ //2 private String prefix=""; private String extension=""; public DirFilter(String filterstr, File dir) { filterstr = filterstr.toLowerCase(); //取前缀 int i= filterstr.indexOf('*'); if(i>0){ this.prefix = filterstr.substring(0,i); } //取后缀 int j= filterstr.lastIndexOf('.'); this.extension = filterstr.substring(j+1); if(this.extension.equals("*")){ this.extension=""; } System.out.println(dir.getAbsolutePath()+"目录中,"+"的文件如下:"); String fileNames[] = dir.list(this); //1 for(String fName:fileNames){ System.out.println(fName); } } public static void main(String[] args) { new DirFilter("*.Java",new File(".","src/cn/hncu/inOut/p29")); JFileChooser jf = new JFileChooser(); jf.showOpenDialog( new JFrame() ); } public boolean accept(File dir, String fileName) { fileName = fileName.toLowerCase(); return fileName.startsWith(this.prefix) && fileName.endsWith(extension); } }
(4)随机存取文件类
public class RandomAccessFile extends Object implements DataOutput, DataInput, Closeable { public RandomAccessFile(String name, String mode) throws FileNotFoundException public RandomAccessFile(File file, String mode) throws FileNotFoundException public final int readInt() throws IOException //读一个整数类型值,当读到文件尾时,抛出EOFException异常 public final void writeInt(int v) throws IOException //写入一个整型值 public long length() throws IOException //返回文件长度 public long getFilePointer() throws IOException //获取文件指针位置 public void seek(long pos) throws IOException //设置文件指针位置 public void close() throws IOException //关闭文件 }
数据字节流ex
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class MyDataInOutputStream { public static void main(String[] args) { // writeToFile(); readFromFile(); } private static void writeToFile() { OutputStream fout = null; DataOutputStream dout = null; try { fout = new FileOutputStream("d:\\ex\\a\\a.txt");//目录必须已存在 dout = new DataOutputStream(fout); for(int i=1;i<=100;i++){ dout.writeInt(i); } } catch (FileNotFoundException e) { e.printStackTrace(); }catch (Exception e) { }finally{ try { fout.close(); dout.close(); } catch (IOException e) { System.out.println("文件无法关闭"); } } } private static void readFromFile() { FileInputStream fin = null; DataInputStream din = null; try { fin = new FileInputStream("d:\\ex\\a\\a.txt"); din = new DataInputStream(fin); while(din.available()>0){ System.out.print( din.readInt() +" "); } System.out.println(); } catch (FileNotFoundException e) { e.printStackTrace(); }catch (Exception e) { }finally{ try { fin.close(); din.close(); } catch (IOException e) { System.out.println("文件无法关闭"); } } } }
import java.io.File; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; public class MyObjectOutputStream extends ObjectOutputStream { //定义成静态的好处 private static File f; public static MyObjectOutputStream newInstance(File file, OutputStream out) throws IOException { f = file;//本方法最重要的地方:构建文件对象,是两个文件对象属于同一个 return new MyObjectOutputStream(out, f); } @Override protected void writeStreamHeader() throws IOException { if (!f.exists() || (f.exists() && f.length() == 0)) { super.writeStreamHeader(); } else { super.reset(); } } public MyObjectOutputStream(OutputStream out, File f) throws IOException { super(out); } }
文件字节流ex
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class MyFileInOutputStream { public static void main(String[] args) { //readFromFile(); writeToFile(); } private static void readFromFile() { byte buffer[] = new byte[512]; int num=0; try { FileInputStream in = new FileInputStream("D:\\ex\\a\\a.txt"); num = in.read(buffer); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch(Exception e){ e.printStackTrace(); } for(int i=0;i<num;i++){ //System.out.print(buffer[i]+" "); System.out.print((char)buffer[i]+" "); } //System.out.println(); } private static void writeToFile(){ try { //FileOutputStream out = new FileOutputStream("d:/ex/a/b.dat");//覆盖 FileOutputStream out = new FileOutputStream("d:/ex/a/b.dat",true);//追加 byte[] buffer = {13,10,97,98,99,100,101,102,49,55}; out.write(buffer); } catch (FileNotFoundException e) { e.printStackTrace(); }catch (Exception e) { e.printStackTrace(); } } }
管道字节流(模拟发牌器)ex
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class SendCard { PipedInputStream[] in; PipedOutputStream[] out; int data[][]; //data[n][max/n],保存n个接收线程分别保存的牌 public SendCard(int max, int n) throws IOException{ in = new PipedInputStream[n]; out = new PipedOutputStream[n]; for(int i=0;i<n;i++){ in[i] = new PipedInputStream(); out[i] = new PipedOutputStream(in[i]); } Sender s = new Sender(out,max); s.start(); data = new int[n][max/n]; for(int i=0; i<n; i++){ new Receiver(in[i],data[i]).start(); } } public void print(){ System.out.println(); for(int i=0;i<data.length; i++){ System.out.print("Receiver"+(i+1)+": "); for(int j=0; j<data[i].length; j++){ System.out.print(data[i][j]+" "); } System.out.println(); } } public static void main(String[] args) { try { SendCard sc = new SendCard(52,4); Thread.sleep(1); sc.print(); } catch (Exception e) { e.printStackTrace(); } } }结果:Sender:
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class FileCopyStream { public static void main(String[] args) { //fileCopy0("b.dat","d:/ex/a/","d:/ex/b/"); //fileCopy1("b.dat","d:/ex/a/","d:/ex/b/"); //fileCopy2("b.dat","d:/ex/a/","d:/ex/b/"); fileCopy3("1.mp3","d:/ex/a/","d:/ex/b/"); //fileCopy3("c.mp3","d:/ex/a/","d:/ex/b/"); //fileCopy3("d.txt","d:/ex/a/","d:/ex/b/"); } private static void fileCopy0(String fileName, String dir1,String dir2){ try { FileInputStream in = new FileInputStream(dir1+fileName); FileOutputStream out = new FileOutputStream(dir2+fileName); byte[] buffer = new byte[512]; in.read(buffer); out.write(buffer); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { } } //学习关流 private static void fileCopy1(String fileName, String dir1,String dir2){ FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream(dir1+fileName); out = new FileOutputStream(dir2+fileName); byte[] buffer = new byte[512]; in.read(buffer); out.write(buffer); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { }finally{ try { in.close(); out.close(); } catch (IOException e) { throw new RuntimeException("文件无法关闭"); } } } //能够拷贝大文件 private static void fileCopy2(String fileName, String dir1,String dir2){ FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream(dir1+fileName); out = new FileOutputStream(dir2+fileName); byte[] buffer = new byte[512]; int num = 0; do{ num = in.read(buffer); out.write(buffer,0,num); }while(num>=0); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }finally{ try { in.close(); out.close(); } catch (IOException e) { throw new RuntimeException("文件无法关闭"); } } } //能够拷贝大文件 private static void fileCopy3(String fileName, String dir1,String dir2){ FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream(dir1+fileName); out = new FileOutputStream(dir2+fileName); byte[] buffer = new byte[512]; int num=0; while(in.available()>0){ num = in.read(buffer); //最简单的加密 for(int i=0;i<num;i++){ buffer[i] = (byte)(buffer[i]+1); } out.write(buffer,0,num); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { }finally{ try { in.close(); out.close(); } catch (IOException e) { throw new RuntimeException("文件无法关闭"); } } } }
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class MyReaderWriter { private static final String LINE_SEPARATOR = System .getProperty("line.separator"); public static void main(String[] args) { try { // writeToFile(); //readFromFile(); copyFile(); } catch (IOException e) { e.printStackTrace(); } // writeToFile2(); } private static void writeToFile() throws IOException { FileWriter fw = new FileWriter("aw.txt"); fw.write("abcdkk"); // fw.write("\n"); // fw.write("\r\n"); fw.write(LINE_SEPARATOR); fw.write("城市海陆空"); // fw.flush(); fw.close(); } /* 用字符流写文件,模板 */ private static void writeToFile2() { FileWriter fw = null; try { fw = new FileWriter("aw.txt"); fw.write("abcdkk"); fw.write(LINE_SEPARATOR); fw.write("城市海陆空"); fw.flush(); } catch (Exception e) { e.printStackTrace(); } finally { if (fw != null) { try { fw.close(); } catch (IOException e) { throw new RuntimeException("关闭失败!"); } } } } private static void readFromFile() throws IOException { FileReader fr = new FileReader("aw.txt"); //char c = (char) fr.read(); //System.out.println(c); char[] buffer = new char[1024]; int num; while((num=fr.read(buffer))!=-1){ System.out.println( new String(buffer,0,num) ); } } //用字符流拷贝,是不能拷非文本文件,会失真! private static void copyFile() throws IOException{ FileReader fr = new FileReader("d:/ex/a/a.txt"); FileWriter fw = new FileWriter("d:/ex/a/b.txt"); char[] buffer = new char[512]; int len=0; while((len=fr.read(buffer))!=-1){ fw.write(buffer, 0, len); } fw.close(); fr.close(); } }
new RandomAccessFile()之后,若文件不存在会自动创建,存在则不创建。——该类其实内部既封装了字节输入流,又封装了字节输出流。
该类若用write()方法写整数,每次只写它的最后一个字节。而采用writeInt()方法,则可把一个整数完整地写入。
通过seek方法设置数据的指针就可以实现对文件数据的随机读写。InputStream中的skip()方法只能从头往后跳,不能反向;而seek()方法可双向随便定位。
用RandomAccessFile类可以实现数据的修改,当然文件中的数据一般要有规律,以方便在编程时能够进行定位,让数据写对地方。 而用“流”实现数据修改时,则通常需要把数据从流读到数组当中,在数组中进行数据修改,然后再把修改后的数组
再重新写到流中。
/* * 用IO流读取数据时,游标是会自动走的。 * 而RandomAccessFile的游标是不会自动向前移动的,要自己控制的 * * 1)用RandomAccessFile类访问数据表记录的速度比Object流更快,因为后者查找匹配的是一个对象 * 2)InputStream类中的skip()方法只能从头往后跳,不能反向。而RandomAccessFile类中的seek()定位,可以双向随意定位。 * 3)如果存储的数据有规律(比如,数据库表中的数据),应该采用RandomAccessFile */ import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; public class RandomAcessFileDemo4 { public static void main(String[] args) { write2File(); readFromFile(); } private static void write2File() { RandomAccessFile rf = null; try { rf = new RandomAccessFile("d:/ex/a/r4.txt", "rw"); for(int i=0;i<10;i++){ rf.writeDouble(3.14f*i); } rf.seek(16);//绝对定位 rf.writeDouble(0); rf.seek(rf.length()); for (int i = 1; i <= 5; i++) { rf.writeInt(15*i); rf.writeByte(5*i); } } catch (IOException e) { e.printStackTrace(); } finally { if (rf != null) { try { rf.close(); } catch (IOException e) { throw new RuntimeException("关流失败"); } } } } private static void readFromFile() { RandomAccessFile rf = null; try { rf = new RandomAccessFile("d:/ex/a/r4.txt", "r"); // long pointer = 0;//自己控制游标 // long len = rf.length(); // //rf.skipBytes(2);//写入的是浮点,不需要跳 // while (pointer < len) { // double d = rf.readDouble(); // System.out.println(d); // pointer = rf.getFilePointer(); // } // rf.seek(48); // double d = rf.readDouble(); // System.out.println(d); rf.seek(85); int x = rf.readInt(); System.out.println(x); } catch (IOException e1) { e1.printStackTrace(); } finally { if (rf != null) { try { rf.close(); } catch (IOException e) { throw new RuntimeException("关流失败"); } } } } }
将一个对象存放到某种类型的永久存储器上称为保持。如果一个对象可以被存放到磁盘或磁带上,或者可以发送到另外一台机器并存放到存储器或磁盘上,那么这个对象就被称为可保持的。(在Java中,序列化、持久化、串行化是一个概念。)
java.io.Serializable接口没有任何方法,它只作为一个“标记者”,用来表明实现了这个接口的类可以考虑串行化。类中没有实现Serializable的对象不能保存或恢复它们的状态。
当一个对象被串行化时,只有对象的数据被保存;方法和构造函数不属于串行化流。如果一个数据变量是一个对象,那么这个对象的数据成员也会被串行化。树或者对象数据的结构,包括这些子对象,构成了对象图。
防止对象的属性被序列化。
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class TestSerializable { public static void main(String[] args) { //序列化---写(输出)到永久存储器 FileOutputStream fout = null; try { fout = new FileOutputStream("a.txt"); ObjectOutputStream out = new ObjectOutputStream(fout); //Address类必须要实现Serializable接口,否则不能序列化 // out.writeObject(new Address("aa",11,"12345678908")); // out.writeObject(new Address("bb",22,"12345888888")); // out.writeObject(new Address("cc",33,"12345666666")); // out.writeObject(new Address("dd",44,"12345777777")); out.writeObject(new Address(1,"aa",11,"12345678908")); out.writeObject(new Address(5,"bb",22,"12345888888")); //线程Thread本身是没有实现Serializable接口的,因此不能序列化 //Thread t1 = new Thread(); //out.writeObject(t1); //如果自定义线程类实现了Serializable接口,则可以序列化 MyThread mt1 = new MyThread(); out.writeObject(mt1); //反序列化----从永久存储器读取(输入)数据 FileInputStream fin = new FileInputStream("a.txt"); ObjectInputStream in = new ObjectInputStream(fin); System.out.println(in.readObject()); System.out.println(in.readObject()); System.out.println(in.readObject()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }finally{ if(fout!=null){ try { fout.close(); } catch (IOException e) { throw new RuntimeException("关流失败!"); } } } } } class Address implements Serializable{ transient int num; //瞬时变量,不会被序列化 String name; int age; String tel; public Address(int num, String name, int age, String tel) { this.num = num; this.name = name; this.age = age; this.tel = tel; } @Override public String toString() { return "Address [num=" + num + ", name=" + name + ", age=" + age + ", tel=" + tel + "]"; } } class MyThread extends Thread implements Serializable{ }
方式1:(方案1是最优的)
DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream("Test.txt") );
方式2:
DataInputStream in = new DataInputStream( new FileInputStream("Test.txt") );
方式3:
BufferedInputStream in = new BufferedInputStream( new DataInputStream( new FileInputStream("Test.java") );1)有buffer比没有更快;
2)buffer放在中间层包装比放在外层更快;
3)按行或按块操作 比 按字节或字符操作更快(用Object流操作的速度 比 字节字符方式 更快)
4)缓冲区要结合流才可以使用,在流的基础上对流的功能进行了增强。
import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; public class BufferedStreamDemo { public static void main(String[] args) { try { //testRead1(); //testRead2(); testRead3(); } catch (Exception e) { e.printStackTrace(); } } public static void testRead1() throws Exception{ long t1 = System.currentTimeMillis();//起始时间 DataInputStream din = new DataInputStream( new BufferedInputStream( new FileInputStream("test.xyz"))); String strLine=""; while((strLine=din.readLine())!=null ){ System.out.println(strLine); } long t2 = System.currentTimeMillis();//终止时间 System.out.println("case1-time:"+(t2-t1)); } public static void testRead2() throws Exception{ long t1 = System.currentTimeMillis();//起始时间 DataInputStream din = new DataInputStream( new FileInputStream("test.xyz")); String strLine=""; while((strLine=din.readLine())!=null ){ System.out.println(strLine); } long t2 = System.currentTimeMillis();//终止时间 System.out.println("case2-time:"+(t2-t1)); } public static void testRead3() throws Exception{ long t1 = System.currentTimeMillis();//起始时间 BufferedInputStream din = new BufferedInputStream( new DataInputStream( new FileInputStream("test.xyz"))); byte bs[] = new byte[din.available()]; din.read(bs); System.out.println(new String(bs)); long t2 = System.currentTimeMillis();//终止时间 System.out.println("case3-time:"+(t2-t1)); } }
例:需求:模拟英文聊天程序,要求:
(1) 从键盘录入英文字符,每录一行就把它转成大写输出到控制台;
(2) 保存聊天记录到字节流文件。
要求1的设计分析:a)需要从键盘接收录入,得用System.in,它是字节输入流InputStream;
b)需要处理字符,可以自己把字节强转成字符,也可以用字符流;
c)需要类似readLine的功能,而这个方法在字符流BufferedReader中有(而且该类有缓冲增速)。
综上,采用转换流把字节流转成字符流处理比较合理,即使用InputStreamReader
要求2的设计分析:
a)需要把字符数据按行保存到字节流文件 ;
b)字符流采用BufferedWriter比较合适,因为它有newLine方法且能实现高效;
c)字节流文件,得采用FileOutputStream。
综上,采用转换流把字符流转成字节流处理比较合理,即使用OutputStreamWriter
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class TransStreamDemo { public static void main(String[] args) throws IOException { //输入 InputStream in = System.in; //System.out.println(in.read()); InputStreamReader isr = new InputStreamReader(in); BufferedReader bufr = new BufferedReader(isr); //String str =bufr.readLine(); //输出 FileOutputStream fout = new FileOutputStream("files\\out.txt",true); OutputStreamWriter osw = new OutputStreamWriter(fout); BufferedWriter bufw = new BufferedWriter(osw); //聊天 String line=null; while( (line=bufr.readLine())!=null){ // if(line.equals("over")){ // break; // } if("over".equals(line)){//一个好的习惯:把字符串常量放在前面 break; } System.out.println(line.toUpperCase()); bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush(); } //关流 bufw.close(); osw.close(); fout.close(); bufr.close(); isr.close(); } }
a)采用FileWriter以默认方式编码
FileOutputStream+默认编码表
b)采用转换流以默认方式编码
OutputStreamWriter + FileOutputStream + 默认编码表
c)采用转换流以指定编码方式编码
OutputStreamWriter + FileOutputStream +指定编码表
d)采用转换流以指定编码方式解码
InputStreamReader + FileInputStream +指定编码表
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class TransStreamDemo2 { public static void main(String[] args) { try { //readTestDecoding(); writeTextEncoding(); } catch (IOException e) { e.printStackTrace(); } } public static void readTestDecoding() throws IOException{ //FileReader fr = new FileReader("files\\utf8.txt");//采用默认编码表来解码(而且在MyEclipse中可以更改默认编码) //FileReader fr = new FileReader("files\\gbk.txt"); // char cbuf[] = new char[50]; // int len = fr.read(cbuf); // String str = new String(cbuf,0,len); // System.out.println(str); // fr.close(); //通过转换流解决乱码 InputStreamReader isr = new InputStreamReader(new FileInputStream("files\\gbk.txt"), "gbk"); //InputStreamReader isr = new InputStreamReader(new FileInputStream("files\\utf8.txt"), "utf-8"); char buf[] = new char[50]; int len2 = isr.read(buf); String str2 = new String(buf,0,len2); System.out.println(str2); isr.close(); } //输出流,字符流的编码解决方案 public static void writeTextEncoding() throws IOException{ //第一种 (使用默认编码表 ) FileWriter fw = new FileWriter("files\\gbk-1.txt"); fw.write("每天进步一点点..."); fw.close();//内部含flush()的功能 //第二种(相当于 FileOutputStream+默认编码表 ) OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("files\\gbk-2.txt")); osw.write("每天进步一点点22222..."); osw.close();//内部含flush()的功能 //第三种(既明确字节输出流,又明确编码表 ) OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("files\\wutf8-1.txt"),"utf-8"); osw2.write("每天进步一点点22222..."); osw2.close();//内部含flush()的功能 } }
1)只有输出没有输入。PrintStream是字节打印流,PrintWriter是字符打印流。
2)能够方便地打印各种数据“值表示形式”,提供了一系列的打印功能(只有它有,其它流都没有。)
3)和其他输出流不同,它永远不会抛出IOException异常(构造方法除外),异常内部解决且设置了内部标志。
4)可创建具有自动刷新的功能,可使用带换行符的println()方法。
5)(在构造方法中)可以指定字符集编码的。
import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; public class PrintStreamDemo { public static void main(String[] args) { /* try { printStreamDemo(); } catch (IOException e) { e.printStackTrace(); } */ PrintStream outBak = System.out; changeOut(null); for(int i=1;i<=10;i++){ System.out.println(i); } changeOut(outBak); for(int i=100;i<=110;i++){ System.out.println(i); } } public static void printStreamDemo()throws IOException{ PrintStream out = new PrintStream("aa.txt"); //out.write(97);//输出该整数的最后一个字节 :97 //out.write(353);//只输出该整数的最后一个字节 : 97 用于计算机内部处理的 out.print(97);//输出该整数的值的表现形式:'9'和'7' 用于给人看的 //out.print(35378332); } /* void print(int i){ out.write(String.valueOf(i)); } */ public static void changeOut(PrintStream out0){ PrintStream out=null; if(out0!=null){ System.setOut(out0); }else{ try { out = new PrintStream("aa2.log"); System.setOut(out); } catch (FileNotFoundException e) { e.printStackTrace(); } } } }
只有遇到结束字符(换行符)时才会自动刷新,如在调用其中一个println方法或写入换行符或字节('\n)时会自动刷新输出缓冲区。
import java.io.BufferedReader; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; public class PrintWriterDemo { public static void main(String[] args) throws IOException{ //encodingDemo(); //autoFlushDemo(); autoFlushDemo2(); } private static void encodingDemo() throws IOException { //PrintWriter out = new PrintWriter("gbk.txt");//用默认编码表 //PrintWriter out = new PrintWriter("gbk.txt","utf-8");//指定编码表 PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream("gbk.txt"),"utf-8"));//要指定编码表,建议最好采用转换流,因为它就是专门用来指定编码的 out.print("中国人民共和国"); out.close(); //字符输出流,一定要刷新flush()。close()方法中带有flush() } private static void autoFlushDemo(){ PrintWriter out = new PrintWriter(System.out,true);//(1)默认不自动刷新,因此下面还是要手动写flush() out.print("Hello World!"); out.flush(); PrintWriter out2 = new PrintWriter(System.out,true);//(2)默认不自动刷新,因此下面还是要手动写flush() out2.print("Hello World2!");//不会自动刷新 out2.print("Hello World2!\n");//还是不会自动刷新 out2.println("Hello World3!");//“会”自动刷新 //println,pringf,format会自动刷新 } //需求:将键盘录入的英文字符转成大写并按行存储到文件中,且带自动刷新功能 private static void autoFlushDemo2()throws IOException{ BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //PrintWriter out = new PrintWriter(new FileWriter("recod.txt"));//默认不带自动刷新 PrintWriter out = new PrintWriter(new FileWriter("recod.txt"),true);//默认不带自动刷新 String line = null; while((line=bufr.readLine())!=null){ if("over".equalsIgnoreCase(line)){ break; } //out.write(line.toUpperCase()+"\r\n"); //out.flush(); out.println(line.toUpperCase()); } } }
1、SequenceInputStream ——对多个流进行合并
将多个流进行逻辑串联(合并变成一个流,操作起来很方便,因为多个源变成了一个源)
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.SequenceInputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; public class SequenceInputStreamDemo { public static void main(String[] args) throws IOException{ FileInputStream fis1 = new FileInputStream("filesequences\\seq1.txt"); FileInputStream fis2 = new FileInputStream("filesequences\\seq2.txt"); FileInputStream fis3 = new FileInputStream("filesequences\\seq3.txt"); //需要枚举对象,通过Collections.enumeration(Collection t)来实现 ArrayList<FileInputStream> v = new ArrayList<FileInputStream>(); v.add(fis1); v.add(fis2); v.add(fis3); Enumeration<FileInputStream> en = Collections.enumeration(v); SequenceInputStream sis = new SequenceInputStream(en); FileOutputStream fos = new FileOutputStream("filesequences\\merge.txt"); byte buf[] = new byte[1024]; int len=0; while((len=sis.read(buf))!=-1){ fos.write(buf, 0, len); } fos.close(); sis.close(); } }
ByteArrayInputStream与ByteArrayOutputStream
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; public class ByteArrayStreamDemo { public static void main(String[] args) { ByteArrayInputStream bis = new ByteArrayInputStream("dssd2323232".getBytes()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); int ch=0; while((ch=bis.read())!=-1){ bos.write(ch); } System.out.println( bos.toString() ); } }
a、流是用来处理数据的。
b、处理数据时,一定要先明确数据源与数据目的地(数据汇)。
c、数据源可以是文件、键盘或者其他流。
d、数据目的地可以是文件、显示器或者其他流。
e、流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理、转换处理等。
使用要点:看顶层(父类共性功能),用底层(子类具体对象)。
命名规律:每个子类的后缀名都是所属体系的父类的名称,很容易区分所属的体系。
而且每一个子类前缀名都是该子类对象的功能体现。
(掌握IO流体系的要点和规律,开发时设计与查找相应的类就容易多了)
源:InputStream Reader 一定是被读取的。
目的:OutputStream Writer 一定是被写入的。
是:使用字符流。Reader Writer
否:使用字节流。 InputStream OutputStream
(到这里,两个明确确定完,就可以确定出要使用哪个体系。接下来,就应该明确具体这个体系要使用哪个具体的对象。【所谓的看顶层】)
源设备:
键盘(System.in)
硬盘(FileXXX)FileReader FileInputStream
内存(数组)ByteArrayInputStream CharArrayReader StringReader
网络(Socket)
目的设备:
显示器(控制台System.out)
硬盘(FileXXX)FileWriter FileOutputStream
内存(数组)ByteArrayOutputStream CharArrayWriter StringWriter
网络(Socket)
(到这里,具体使用哪个对象就可以明确了。【所谓的用底层】)
1) 是否需要高效?缓冲区Buffered (字符与字节各两个)
2) 是否需要转换?转换流 InputStreamReader OutputStreamWriter
3) 是否操作基本数据类型? DataInputStream DataOutputStream
4) 是否操作对象(对象序列化)? ObjectInputStream ObjectOutputStream
5) 需要对多个源合并吗? SequenceInputStream
6) 需要保证数据的表现形式到目的地吗? PrintStream 或 PrintWriter
(到这里,具体的设计方案就可以明确了。【套接与功能加强】)
需求1:复制一个文本文件。
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、处理的数据是否是纯文本的数据?
源:Reader
目的:Writer
3、明确数据所在的设备。
源:file(硬盘) FileReader fr = new FileReader("a.txt");
目的:file(硬盘) FileWriter fw = new FileWriter("b.txt");
4、明确是否需要额外功能?
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
需求2:复制一个图片文件。
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、处理的数据是否是纯文本的数据?
源:Reader
目的:Writer
3、明确数据所在的设备。
源:file(硬盘) FileReader fr = new FileReader("a.txt");
目的:file(硬盘) FileWriter fw = new FileWriter("b.txt");
4、明确是否需要额外功能?
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
需求3:读取键盘录入,存储到一个文件中。
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、处理的数据是否是纯文本的数据?
源:Reader
目的:Writer
3、明确数据所在的设备。
源:file(硬盘) InputStream in = System.in; 原因:必须要将键盘录入的字节转成字符。需要将字节-->字符的转换流。InputStreamReader
目的:file(硬盘) FileWriter fw = new FileWriter("b.txt");
4、明确是否需要额外功能?
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("a.txt");
高效:BufferedReader bufr = new BufferedReader( isr);
BufferedWriter bufw = new BufferedWriter( fw );
需求4:读取一个文本文件,显示到显示器上。
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、处理的数据是否是纯文本的数据?
源:Reader
目的:Writer
3、明确数据所在的设备。
源:file(硬盘) FileReader fr = new FileReader("a.txt");
目的:显示器 OutputStream out = System.out; 原因:要将字符数据转换成字节输出。输出转换流:OutputStreamWriter
4、明确是否需要额外功能?
FileReader fr = new FileReader("a.txt");OutputStreamWriter osw = new OutputStreamWriter(System.out);
高效:BufferedReader bufr = new BufferedReader( fr);
BufferedWriter bufw = new BufferedWriter( osw );
需求5:读取一个文本文件,将文本按照指定的编码表UTF-8写入到另一个文件中
1、明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、处理的数据是否是纯文本的数据?
源:Reader
目的:Writer
3、明确数据所在的设备。
源:file(硬盘) FileReader fr = new FileReader("a.txt");
目的:file(硬盘) FileOutputStream fout = new FileOutputStream("b.txt")原因:假定输出时要为字符数据指定编码表。转换流中的参数需要字节流,因此用转换流:FileOutputStream。
4、明确是否需要额外功能?
FileReader fr = new FileReader("a.txt");OutputStreamWriter osw = new OutputStreamWriter(fout,”utf-8”);
高效:BufferedReader bufr = new BufferedReader( fr);
BufferedWriter bufw = new BufferedWriter( osw );
点击打开链接
点击打开链接
虽然看上去很多,其实仔细看看也没什么,无非是看懂加强片中的八中所讲的内容,就可以随手写io了。