java基础---->I/O
IO操作作为整个JAVA中最复杂的开发包,但是要想跨过此部分,就必须对面向对象的基本概念非常的熟悉,对于抽象类也要熟悉。
根据实例化子类的不同,完成的功能也不同。这句话就是IO操作的核心。
整个IO包中实际上需要的就是五个类和一个接口:File、OutputStream、InputStream、Writer、Reader;Serializable。
所有的类和接口基本上都在java.io包中定义的。
在IO操作记住:输出的时候使用PrintStream,输入的时候使用Scanner。
一、File类
File类的构造:publicFile(String pathname),在建立File对象的时候需要指定一个路径。
现在要想创建一个文件,可以使用方法:public booleancreateNewFile() throwsIOException
import java.io.File; public class FileDemo01 { public static void main(String[] args)throws Exception { File file = new File("d:\\temp.txt");// 指定要操作的文件路径 file.createNewFile(); } }
既然可以创建文件,那肯定也可以删除:public boolean delete()
但是如果要想删除文件,则肯定要判断文件是否存在:public boolean exists()
那么下面完成这样的一个程序:如果文件存在,则删除掉,如果文件不存在,则创建新的。
import java.io.File; public class FileDemo01 { public static void main(String[] args)throws Exception { File file = new File("d:\\temp.txt");// 指定要操作的文件路径 if (file.exists()) { file.delete(); // 删除文件 } else { file.createNewFile();// 创建新文件 } } }
但是在创建和删除文件的时候发现会出现延迟的问题,因为JAVA运行机制是运行在JVM上,由JVM进行OS的具体的适应,所以中间存在延迟,而且本程序也有问题,在Java的最大特点是可移植性,但是在不同的操作系统中路径的分割符肯定是不一样的:
· windows中使用“\”
· linux中使用“/”
那么要想解决这样的问题,就必须观察File类定义的常量:public static final String separator。
separator是一个常量,按照常量的命名要求肯定全部的字母都要大写:SEPARATOR。这些都是由于Java发展的历史原因所造成的问题。
File file = new File("d:" + File.separator + "temp.txt");// 指定要操作的文件路径
由于在给定文件的路径上有可能给出的是一个文件,也有可能给出的是一个文件夹,那么为了判断,在File类中提供了以下的两个方法:
·判断是否是文件: public boolean isFile()
·判断是否是文件夹: public boolean isDirectory()
范例:判断类型
import java.io.File; public class FileDemo02 { public static void main(String[] args)throws Exception { File file1 = new File("d:" + File.separator + "temp.txt");// 指定要操作的文件路径 File file2 = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径 System.out.println(file1.isFile()); System.out.println(file2.isDirectory()); } }
在File类的操作中可以通过代码列出一个文件夹之中的完整内容,方法如下:
·列出文件或文件夹的名称:public String[] list()
·列出完整的路径,而且返回的是File类的对象:public File[] listFiles()
范例:使用list()方法
import java.io.File; public class FileDemo03 { public static void main(String[] args)throws Exception { File file = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径 if (file.isDirectory()) {// 如果是文件夹,则列出内容 String list[] = file.list();// 列出全部的内容 for (int x = 0; x < list.length; x++) { System.out.println(list[x]); }}}}
范例:使用listFiles()完成列表
import java.io.File; public class FileDemo03 { public static void main(String[] args)throws Exception { File file = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径 if (file.isDirectory()) {// 如果是文件夹,则列出内容 File list[] = file.listFiles() ; // 列出全部内容 for (int x = 0; x < list.length; x++) { System.out.println(list[x]); }}}}
使用listFiles()方法输出的时候可以输出一个完整的路径,而且返回的是File类的对象,可以进行更多的操作。
import java.io.File; publicclass FileDemo03 { public static void main(String[] args)throws Exception { File file = new File("d:" + File.separator + "testjava");// 指定要操作的文件路径 if (file.isDirectory()) {// 如果是文件夹,则列出内容 File list[] = file.listFiles() ; // 列出全部内容 for (int x = 0; x < list.length; x++) { System.out.println(list[x] +" --> " + list[x].length()); }}}}
思考题:
现在要求输出一个给定目录中的全部文件的路径。
本程序肯定只能依靠递归的操作完成,因为在一个给定的路径下有可能还是文件夹,那么如果是文件夹的话则肯定要继续列出,重复判断。
import java.io.File; public class ListFileDemo { public static void main(String[] args) { File file = new File("D:" + File.separator); list(file); } public static void list(File file) { if (file.isDirectory()) {// 如果是文件夹,则继续列出 File f[] = file.listFiles(); if (f !=null) {// 文件夹的内容已经列出 for (int x = 0; x < f.length; x++) { list(f[x]);// 继续列出每一个内容 } } } System.out.println(file); } }
二、字节流与字符流
File类本身是与文件操作有关,但是如果要想操作内容则必须使用字节流或字符流完成,但是不管是使用何种的输入输出流,其基本的操作原理是一样的(以文件流为准)
1、 使用File类找到一个文件
2、 通过字节流或字符流的子类进行对象的实例化
3、 进行读或写的操作
4、 关闭字节或字符流
由于流的操作属于资源操作,所以在操作的最后一定要关闭以释放资源。
操作流有以下几个:
·字节流:OutputStream、InputStream
·字符流:Writer、Reader
2.1、字节输出流
字节输出流使用的是OutputStream,此类定义如下:
public abstract class OutputStream extends Object implements Closeable, Flushable
本类是一个抽象类,根据面向对象的概念,要通过子类进行对象的实例化操作。
在此类中定义了如下的几个常用方法:
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 {} //关闭输出流,空方法 }
但是要想为OutputStream实例化,且进行文件操作的话,就要使用FileOutputStream子类。
·构造:public FileOutputStream(File file) throwsFileNotFoundException
范例:使用字节流进行输出,输出“HelloWorld”。
import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; public class OutputStreamDemo01 { public static void main(String[] args)throws Exception { // 1、通过File找到一个文件 File file = new File("d:" + File.separator + "temp.txt"); // 2、实例化OutputStream对象 OutputStream out = new FileOutputStream(file); String info = "Hello World!!!"; //要输出的字符串 byte data[] = info.getBytes();// 将字符串变为字节数组 out.write(data); // 输出内容 out.close(); } }
现在已经可以向文件中输出内容了,但是此时程序每执行一次,实际上都会输出,但是属于覆盖的操作,如果要想在文件的尾部追加的话,则必须观察FileOutputStream类的另外一个构造:
·追加:public FileOutputStream(File file,boolean append) throwsFileNotFoundException
如果需要在追加的上面加入换行的话,使用“\r\n”。
import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; public class OutputStreamDemo01 { public static void main(String[] args) throws Exception { // 1、通过File找到一个文件 File file = new File("d:" + File.separator + "temp.txt"); // 2、实例化OutputStream对象 OutputStream out = new FileOutputStream(file, true); // 追加 String info = "\r\nHello World!!!"; // 要输出的字符串 byte data[] = info.getBytes(); // 将字符串变为字节数组 out.write(data); // 输出内容 out.close(); } }
2.2、字节输入流
程序中可以使用OutputStream进行输出的操作,也可以使用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 {} //关闭输入流,空方法 }
类依然是一个抽象类,肯定要使用子类完成,如果是文件输入,使用FileInputStream类。
如果要读,则肯定需要一个数组,数组肯定要首先开辟好大小,用于接收内容。
但是,与OutputStream类似,要读取就要观察FileInputStream类的构造方法:
·构造:public FileInputStream(File file) throwsFileNotFoundException
import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class InputStreamDemo01 { public static void main(String[] args)throws Exception { File file = new File("d:" + File.separator + "temp.txt"); InputStream input = new FileInputStream(file); byte data[] =new byte[1024];// 开辟一个空间 int len = input.read(data);// 接收输入流的内容 System.out.println("内容是:(" + new String(data, 0, len) +")"); } }
以上的代码属于一次性全部读取,但是在InputStream类中也可以每次读取一个字节。
import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class InputStreamDemo02 { public static void main(String[] args)throws Exception { File file = new File("d:" + File.separator + "temp.txt"); InputStream input = new FileInputStream(file); byte data[] =new byte[1024];// 开辟一个空间 int len = 0;// 记录读取的长度 int temp = 0; do { temp = input.read();// 读取一个字节 if (temp != -1) {// 如果不为-1表示内容可以增加 data[len++] = (byte) temp;// 保存在字节数组中 } } while (temp != -1);// 如果不是-1表示还有内容可以读 System.out.println("内容是:(" + new String(data, 0, len) +")"); } }
但是以上的读取方式在开发中会变成另外一种代码形式:
int temp = 0; while ((temp = input.read()) != -1) { data[len++] = (byte) temp; }
2.3、字符输出流
Writer属于字符输出流,Writer类也是一个抽象类,既然要操作文件,肯定使用FileWriter。
import java.io.File; import java.io.FileWriter; import java.io.Writer; public class WriterDemo01 { public static void main(String[] args)throws Exception { File file = new File("d:" + File.separator + "temp.txt"); Writer out = new FileWriter(file); out.write("Hello World");// 直接输出字符串 out.close() ; } }
2.4、字符输入流
Reader也肯定是一个抽象类,要输入文件使用FileReader。
import java.io.File; import java.io.FileReader; import java.io.Reader; public class ReaderDemo01 { public static void main(String[] args)throws Exception { File file = new File("d:" + File.separator + "temp.txt"); Reader read = new FileReader(file); char data[] =new char[1024]; int len = read.read(data); System.out.println(new String(data, 0, len)); } }
2.5、字节流和字符流的区别
Java 流在处理上分为字符流和字节流。字符流处理的单元为2个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和 java 内 Unicode 字符流之间的转换。而类 InputStreamReader 和 OutputStreamWriter 处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。
字节流和字符流在使用上的代码结构都是非常类似的,但是其内部本身也是有区别的,因为在进行字符流操作的时候会使用到缓冲区,而字节流操作的时候是不会使用到缓冲区的。在输出的时候,OutputStream类即使最后没有关闭内容也可以输出。但是如果是Writer的话,则如果不关闭,最后一条内容是无法输出的,因为所有的内容都是保存在了缓冲区之中,每当调用了close()方法就意味着清空缓冲区了。那么可以证明字符流确实使用了缓冲区。如果现在字符流即使不关闭也可以完成输出的话,则必须强制性清空缓冲区:
方法:public void flush()throws IOException
字节流不关闭,但是文件中也依然存在了输出的内容,证明字节流是直接操作文件本身的。
import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; public class OutputStreamDemo05 { public static void main(String[] args) throws Exception { // 异常抛出, 不处理 // 第1步:使用File类找到一个文件 File f = new File("d:" + File.separator + "test.txt"); // 声明File 对象 // 第2步:通过子类实例化父类对象 OutputStream out = null; // 准备好一个输出的对象 out = new FileOutputStream(f); // 通过对象多态性进行实例化 // 第3步:进行写操作 String str = "Hello World!!!"; // 准备一个字符串 byte b[] = str.getBytes(); // 字符串转byte数组 out.write(b); // 将内容输出 // 第4步:关闭输出流 // out.close(); // 此时没有关闭 } }
字符流不关闭
import java.io.File; import java.io.FileWriter; import java.io.Writer; public class WriterDemo03 { public static void main(String[] args) throws Exception { // 异常抛出, 不处理 // 第1步:使用File类找到一个文件 File f = new File("d:" + File.separator + "test.txt");// 声明File 对象 // 第2步:通过子类实例化父类对象 Writer out = null; // 准备好一个输出的对象 out = new FileWriter(f); // 通过对象多态性进行实例化 // 第3步:进行写操作 String str = "Hello World!!!"; // 准备一个字符串 out.write(str); // 将内容输出 // 第4步:关闭输出流 // out.close(); // 此时没有关闭 } }
程序运行后会发现文件中没有任何内容,这是因为字符流操作时使用了缓冲区,而在关闭字符流时会强制性地将缓冲区中的内容进行输出,但是如果程序没有关闭,则缓冲区中的内容是无法输出的,所以得出结论:字符流使用了缓冲区,而字节流没有使用缓冲区。
两者相比,肯定使用字节流更加的方便,而且在程序中像图片、MP3等都是采用字节的方式的保存,那么肯定字节流会比字符流使用的更广泛。但是需要说明的是,如果要是想操作中文的话,字符流肯定是最好使的。
2.6、例子:文件拷贝
现在要求完成一个Copy程序,完全模仿DOS中的拷贝命令。
命令的运行形式,可以通过初始化参数的方式设置两个路径
·形式:java Copy源文件路径目标文件路径
本程序完成有两个思路:
·思路一:将所有的内容全部读取进来,之后一次性保存
·思路二:边读边写
而且要进行读取的时候还要判断源文件是否存在。
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; public class Copy { public static void main(String[] args)throws Exception { if (args.length != 2) { System.out.println("语法命令不正确!"); System.exit(1); } File file1 = new File(args[0]); if (file1.exists()) {// 如果源文件存在 File file2 = new File(args[1]); InputStream input = new FileInputStream(file1); OutputStream output =new FileOutputStream(file2); int temp = 0; while ((temp = input.read()) != -1) {// 边读边写 output.write(temp);// 输出 } input.close(); output.close(); System.out.println("文件拷贝完成。"); } } }
三、内存操作流
之前的文件操作流是以文件的输入输出为主的,但是如果现在将输入输出的位置一改变,改变成了内存,那么就称为内存操作流。使用ByteArrayInputStream完成内存的输入操作,而使用ByteArrayOutputStream完成内存的输出操作,但是一定要注意的是,现在的输入和输出都是以内存为标准的。
ByteArrayInputStream构造:public ByteArrayInputStream(byte[] buf)
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; public class ByteArrayDemo { public static void main(String[] args)throws Exception { String info = "helloworld"; InputStream input = new ByteArrayInputStream(info.getBytes()); OutputStream output = new ByteArrayOutputStream(); int temp = 0; while ((temp = input.read()) != -1) { output.write(Character.toUpperCase((char) temp)); } String str = output.toString(); // 取出内容 input.close() ; output.close() ; System.out.println(str) ; } }
现在虽然完成了内存的操作,但是可以发现现在的IO都是从内存中,也就是说可以将内存当作一个临时的文件进行操作,所以内存操作流一般在产生临时文件内容的时候使用。
四、打印流
思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便?
肯定是不方便的,因为OutputStream中只能操作字节数据,所以其他的数据类型很难操作,那么在Java的IO包中为了解决这种问题增加了两种类:PrintStream、PrintWriter。
4.1、 PrintStream
观察PrintStream类的构造:public PrintStream(OutputStream out)
虽然PrintStream是OutputStream的子类,但是在实例化的时候依然需要一个OutputStream的对象。
在PrintStream中定义了一系列的输出操作,可以方便的完成输出,那么这种设计思路就是装饰设计。
import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; public class PrintStreamDemo01 { public static void main(String[] args)throws Exception { PrintStream out = new PrintStream(new FileOutputStream(new File("d:" + File.separator +"test.txt"))); out.print(1 + " + " + 1 + " = "); out.println(1 + 1); out.println("Hello World!!!") ; } }
在开发中由于PrintStream较为好用,所以只要是输出就使用打印流完成。一些数据的表示格式:%d、%f、%s
import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; public class PrintStreamDemo02 { public static void main(String[] args)throws Exception { PrintStream out = new PrintStream(new FileOutputStream(new File("d:" + File.separator +"test.txt"))); String name = "张三"; int age = 30; float score = 90.89765f; out.printf("姓名:%s,年龄:%d,成绩:%5.2f", name, age, score); } }
4.2、PrintWriter
PrintStream是OutputStream的子类,PrintWriter是Writer的子类,两者处于对等的位置上,PrintWriter是一种过滤流,也叫处理流。也就是能对字节流和字符流进行处理,所以它会有一下的构造方法。
PrintWriter(OutputStream out) 根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。
PrintWriter(Writer out) 创建不带自动行刷新的新 PrintWriter
然后PrintWriter能够直接对文件操作,所以还有这两种构造方法:
PrintWriter(File file) 使用指定文件创建不具有自动行刷新的新 PrintWriter。
PrintWriter(String fileName) 创建具有指定文件名称且不带自动行刷新的新 PrintWrite
import java.io.IOException; import java.io.PrintWriter; import java.io.FileWriter; import java.io.File; public class PrintWriterDemo { public static void main(String[] args) { PrintWriter pw = null; String name = "wsz"; int age = 22; float score = 32.5f; char sex = '男'; try { pw = new PrintWriter(new FileWriter(new File("e:\\file.txt")), true); pw.printf("姓名:%s;年龄:%d;性别:%c;分数:%5.2f;", name, age, sex, score); pw.println(); pw.println("多多指教"); pw.write(name.toCharArray()); } catch (IOException e) { e.printStackTrace(); } finally { pw.close(); } } }
4.3、两者区别
PrintStream是字节流,它有处理byte的方法,write(int)和write(byte[],int,int);PrintWriter是字符流,它没有处理byte的方法。PrintStream和PrintWriter的auto flushing机制有点不同,前者在输出byte数组、调用println方法、输出换行符或者byte值10(即\n)时自动调用flush方法,后者仅在调用println方法时发生auto flushing。
五、System类对IO的支持
在System类中定义了以下的三个常量:
·错误输出:public static final PrintStream err
·屏幕输出:public static final PrintStream out
·键盘输入:public static final InputStream in
5.1、错误输出
System.err表示的是错误的输出,此类型也属于PrintStream类型。
public class SystemErrDemo { public static void main(String[] args) { try { Integer.parseInt("A"); } catch (NumberFormatException e) { System.err.println(e); } } }
使用System.err和System.out的输出是完全一样的,但是在Eclipse中System.err的输出会使用红色表示。两个的区别只是人为的增加的区别,System.err一般是不希望用户看见的错误,而System.out是希望用户看见的错误。
5.2、屏幕输出
System.out属于屏幕输出的操作,对应着显示器,但是可以通过System.out为OutputStream实例化。
import java.io.OutputStream; public class SystemOutDemo { public static void main(String[] args)throws Exception { OutputStream out = System.out ; out.write("hello world".getBytes()) ; } }
5.3、键盘输入
一般的语言中都存在着键盘输入数据的操作,在Java中也有,只是一般来讲这种操作不是现成的,而且必须依靠IO流的操作才能完成,输入靠的是System.in。
import java.io.InputStream; public class SystemInDemo { public static void main(String[] args)throws Exception { InputStream input = System.in;// 可以由键盘输入 byte data[] =new byte[1024]; System.out.print("请输入内容:"); int len = input.read(data); System.out.println("输入的内容是:" + new String(data, 0, len)); } }
此时已经完成了内容的输入,但是本程序有问题,因为现在所有的输入内容都是保存在了data这个字节数组之中,如果现在输入的内容的长度大于数组中的长度的话,则超出的部分无法接收。
这种操作出现问题的主要原因是一开始的数组大小限制了长度,那么如果现在没有长度限制呢?
import java.io.InputStream; public class SystemInDemo { public static void main(String[] args)throws Exception { InputStream input = System.in;// 可以由键盘输入 StringBuffer buf = new StringBuffer(); System.out.print("请输入内容:"); int temp = 0; while ((temp = input.read()) != -1) { char c = (char) temp; if (c =='\n') { break ; } buf.append(c); } System.out.println("输入的内容是:" + buf); } }
这种输入现在只能适合于英文环境上,因为是按照每一个字节的方式读取的,而一个中文是两个字节。
所以,如果要想彻底的解决问题,最好的做法是,将所有的输入内容暂时存放到一个缓冲区之中,之后从缓冲区里一次性将内容全部读取回来。
六、BufferedReader
BufferedReader的主要功能是用于缓冲区读取的,但是有一点,从类的定义上可以发现,此类属于字符输入流,而System.in属于字节流,那么很明显,如果要想使用BufferedReader就需要将一个字节流变成字符流,为了解决这样的问题,在Java中提供了以下的两个转换类:
·将输入的字节流变为字符流:InputStreamReader
·将输出的字符流变为字节流: OutputStreamWriter
在BufferedReader类中提供了一个专门的读取操作:public String readLine() throws IOException
import java.io.BufferedReader; import java.io.InputStreamReader; public class BufferDemo { public static void main(String[] args)throws Exception { BufferedReader buf = new BufferedReader(new InputStreamReader(System.in)); System.out.print("请输入内容:"); String info = null;// 用于接收输入的内容 info = buf.readLine(); // 接收内容 System.out.println(info); } }
由于所有的内容都是从缓冲区一次性读取完成的,那么不会出现乱码问题。以上就是一个键盘输入的标准程序。
七、Scanner类
在JDK 1.5之后为了方便输入,又增加了一个新的类:Scanner,此类并不是在java.io包中定义的,而是在java.util包中定义的public final class Scanner implements Iterator<String>,。使用Scanner可以方便的完成各种字节输入流的输入。
构造:public Scanner(InputStream source)
Scanner类实现了Iterator接口,所以它有以下方法。
boolean hasNext()方法
Object next()方法
void remove()方法
useDelimiter()使用定界符的意思
nextXxx()从流中读取一个Xxx并返回Xxx值。
import java.util.Scanner; public class ScannerDemo01 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.print("请输入内容:"); if (scan.hasNext()) {// 现在有内容 String str = scan.next(); System.out.println("输入的内容是:" + str); } } }
除了这种功能之外,使用Scanner也可以输入各种数据类型,例如:float。
import java.util.Scanner; public class ScannerDemo02 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.print("请输入内容:"); if (scan.hasNextInt()) {// 现在有内容 int str = scan.nextInt(); System.out.println("输入的内容是:" + str); } } }
但是,如果要想进行其他数据格式验证的话,则就需要编写正则表达式完成了。
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; publicclass ScannerDemo03 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.print("请输入日期:"); if (scan.hasNext("\\d{4}-\\d{2}-\\d{2}")) {// 现在有内容 String str = scan.next("\\d{4}-\\d{2}-\\d{2}"); Date date = null; try { date = new SimpleDateFormat("yyyy-MM-dd").parse(str); } catch (ParseException e) { e.printStackTrace(); } System.out.println(date); } } }
使用Scanner类除了可以完成以上的输入之外,也可以从一个文件流中输入内容。
import java.io.File; import java.io.FileInputStream; import java.util.Scanner; public class ScannerFileDemo { public static void main(String[] args)throws Exception { Scanner scan = new Scanner(new FileInputStream(new File("d:"+ File.separator +"test.txt"))); scan.useDelimiter("\n");// 将换行作为分隔符 while (scan.hasNext()) { String str = scan.next(); System.out.print(str); } } }
八、Java IO 的一般使用原则 :
一、按数据来源(去向)分类:
- 是文件: FileInputStream, FileOutputStream, ( 字节流 )FileReader, FileWriter( 字符 )
- 是 byte[] : ByteArrayInputStream, ByteArrayOutputStream( 字节流 )
- 是 Char[]: CharArrayReader, CharArrayWriter( 字符流 )
- 是 String: StringBufferInputStream, StringBufferOuputStream ( 字节流 )StringReader, StringWriter( 字符流 )
- 网络数据流: InputStream, OutputStream,( 字节流 ) Reader, Writer( 字符流 )
二、按是否格式化输出分:
要格式化输出: PrintStream, PrintWriter
三、按是否要缓冲分:
要缓冲:BufferedInputStream, BufferedOutputStream,(字节流) BufferedReader, BufferedWriter(字符流)
四、按数据格式分:
1 、二进制格式(只要不能确定是纯文本的) : InputStream, OutputStream 及其所有带 Stream 结束的子类
2 、纯文本格式(含纯英文与汉字或其他编码方式); Reader, Writer 及其所有带 Reader, Writer 的子类
五、按输入输出分:
1 、输入: Reader, InputStream 类型的子类
2 、输出: Writer, OutputStream 类型的子类
六、特殊需要:
1 、从 Stream 到 Reader,Writer 的转换类: InputStreamReader, OutputStreamWriter
2 、对象输入输出: ObjectInputStream, ObjectOutputStream
3 、进程间通信: PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
4 、合并输入: SequenceInputStream
5 、更特殊的需要: PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader
决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要):
首先,考虑最原始的数据格式是什么: 原则四
第二,是输入还是输出:原则五
第三,是否需要转换流:原则六第1点
第四,数据来源(去向)是什么:原则一
第五,是否要缓冲:原则三 (特别注明:一定要注意的是 readLine() 是否有定义,有什么比 read, write 更特殊的输入或输出方法)
第六,是否要格式化输出:原则二
在IO操作记住:输出的时候使用PrintStream,输入的时候使用Scanner。
总结
1、使用File类可以操作文件,但是在编写文件分隔符的时候要注意使用File.separator
2、字节流和字符流最大的区别在于字符流使用到了缓冲区操作,但是一般字节流使用较多
3、内存流是所有的输入输出都在内存中完成:ByteArrayInputStream、ByteArrayOutputStream
4、如果要输出内容可以使用PrintStream类方便的完成
5、如果要输入内容可以使用Scanner类
6、对象序列化http://blog.csdn.net/ncepustrong/article/details/8125025