IO

来源:互联网 发布:vb 颜色代码 编辑:程序博客网 时间:2024/04/28 00:33

-------android培训 java培训  、期待与您交流-------

IO流
  • Java对数据的操作是通过流的方式
  • IO流用来处理设备之间的数据传输
  • Java用于操作流的对象都在IO包中
  • 流按操作数据分为两种:字节流与字符流。
  • 流按流向分为:输入流,输出流。
  • 字节流的抽象基类:
    • InputStream ,OutputStream
  • 字符流的抽象基类
    • ReaderWriter
字符流
Writer
Writer是写入字符流的顶层类。
Writer中定义的方法:
write(): 向流中写入数据,写入的数据可以是单个字符,字符串或字符串的某一部分,字符数组或字符数组的某一部分,
flush(): 刷新流中的数据,将数据写入到目的地。
close(): 关闭流资源,但是在关闭之前会先刷新流。
FileWriter 
FileWriter是Writer的间接子类,主要用于操作文本文件。

IO异常处理方式
代码示例:
FileWriter fw = null;try {fw = new FileWriter("z://heima.java");fw.write("java");fw.flush();} catch (IOException e) {System.out.println(e.toString());} finally {try {// 如果指定的路径不存在,则FileWriter初始化失败,fw=null,不能调用close()方法。此处必须进行非空判断。// 如果有多个流资源的关闭动作,必须对每个流资源的关闭动作进行非空判断。if (fw != null) {fw.close();//关闭流资源的动作一定要被执行,所以放在finally块中}} catch (IOException e) {System.out.println(e.toString());}}

文本文件的两种读取方式
方式一:一个字符一个字符的读,读取一个字符输出一个字符
int read():  读取单个字符。返回字符所对应的整数,如果读到流的末尾,则返回-1。
示例代码:
FileReader fr = new FileReader("FileWriterDemo.java");int ch = 0;while ((ch = fr.read()) != -1) {System.out.print((char) ch);}fr.close();
方式二:每读取一个字符就存入数组中,然后将数组中的字符输出。
int read(char[] cbuf): 将字符读入数组。返回读取的字符数,如果读到流的末尾,则返回-1。
代码示例:
FileReader fr = new FileReader("FileWriterDemo.java");char[] buffer = new char[1024];int num = 0;while ((num = fr.read(buffer)) != -1) {System.out.print(new String(buffer, 0, num));}fr.close();

 

字符流的两种拷贝方式
拷贝方式一:读一个字符就写入一个字符到流中
示例代码:
FileWriter fw = new FileWriter("heima.java");FileReader fr = new FileReader("FileReaderDemo1.java");int ch = 0;while ((ch = fr.read()) != -1) {fw.write(ch);}fw.close();fr.close();
拷贝方式二:一直读并存入到缓冲区,再一并写入
示例代码:
FileWriter fw = new FileWriter("heima.java");FileReader fr = new FileReader("CopyFileDemo.java");char[] buffer = new char[1024];// 创建一个缓冲int len = 0;while ((len = fr.read(buffer)) != -1) {fw.write(buffer, 0, len);// 写入有效数据}fw.close();fr.close();

拷贝文本文件图列

字符流的缓冲区
  • 缓冲区的出现提高了对数据的读写效率。
  • 对应类
    • BufferedWriter
      • void newLine(): 写入一个行分隔符。
    • BufferedReader
      • String readLine(): 读取一个文本行。返回包含该行内容的字符串,不包含任何行终止符。如果达到流的末尾则返回null。
  • 缓冲区要结合流才能使用。
  • 在流的基础上对流的功能进行了增强。
使用缓冲区的注意事项:
1    先有流对象,才有缓冲区。
2    使用缓冲区,必须调用flush()方法进行刷新。

字节流
字节流的拷贝方式
方式一:自定义一个缓冲区 byte数组 的方式读写数据
示例代码:
FileOutputStream fos = new FileOutputStream("d:\\2.jpg");FileInputStream fis = new FileInputStream("d:\\1.jpg");byte[] buf = new byte[1024];int len = 0;while ((len = fis.read(buf)) != -1) {fos.write(buf, 0, len);}fos.close();fis.close(); 
方式二:通过Java提供的缓冲区对象读写数据
示例代码:
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("d:\\3.jpg"));BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("d:\\1.jpg"));int b = 0;while ((b = bufis.read()) != -1) {bufos.write(b);}bufos.close();bufis.close();
读取键盘录入
System.in:  对应的是标准的输入设备,键盘。
System.out:  对应的是标准的输出设备,控制台。
示例代码:
InputStream in = System.in;StringBuilder sb = new StringBuilder();while (true) {int ch = in.read();if (ch == '\r')continue;if (ch == '\n') {String s = sb.toString();System.out.println(s.toUpperCase());sb.delete(0, sb.length());} else {sb.append((char) ch);}}
改变标准输入输出设备
System.setIn(InputStream in):             重新分配标准输入流。
System.setOut(OutputStream out):        重新分配标准输出流。

转换流

InputStreamReader:    是字节流通向字符流的桥梁
OutputStreamWriter : 是字符流通向字节流的桥梁


 
//获取键盘录入对象InputStream in = System.in;// 将字节流对象转成字符流对象,使用转换流,InputStreamReaderInputStreamReader isr = new InputStreamReader(in);// 为了提高效率,将字符流进行缓冲区技术高效读取,使用BufferedReaderBufferedReader bufr = new BufferedReader(isr);// 键盘录入最常见写法BufferedReader bufr1 = new BufferedReader(new InputStreamReader(System.in));OutputStream out = System.out;OutputStreamWriter osw = new OutputStreamWriter(out);BufferedWriter bufw = new BufferedWriter(osw);// 简写格式:BufferedWriter bufw1 = new BufferedWriter(new OutputStreamWriter(System.out));String line = null;while ((line = bufr.readLine()) != null) {if ("over".equals(line))break;bufw.write(line.toUpperCase());bufw.newLine();bufw.flush();}bufr.close();
流操作规律
通过三个明确来完成。1,明确源和目的。源:输入流。InputStream  Reader目的:输出流。OutputStream  Writer。2,操作的数据是否是纯文本。是:字符流。不是:字节流。3,当体系明确后,在明确要使用哪个具体的对象。通过设备来进行区分:源设备:  内存ArrayStream  硬盘FileStream  键盘System.in目的设备:内存ArrayStream  硬盘FileStream  控制台System.out
4,如果要提高效率则使用缓冲区
5,如果要用指定编码存储数据则使用转换流
 
异常的日志信息
示例代码:
try {int[] arr = new int[2];System.out.println(arr[3]);} catch (Exception e) {try {Date d = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(d);PrintStream ps = new PrintStream("exeception.log");ps.println(s);System.setOut(ps);} catch (IOException ex) {throw new RuntimeException("日志文件创建失败");}e.printStackTrace(System.out);}
File类
File类继承自Object类,是文件和目录路径名的抽象表现形式。
用来将文件或文件夹封装成对象。
方便对文件和文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数。

File类的字段和构造函数:
String File.separator :                    与系统有关的目录分隔符,在windosXP系统中代表“\\”
File(File parent ,String child):      根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例
File(String pathname):                   通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例
File(String parent,String child):      根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。

代码示例:
//将a.txt封装成File对象,可以将已有的和未出现的文件或文件夹封装成对象Fiel f1 = new File("a.txt");File f2 = new File("c:\\abc","b.txt");File d = new File("c:\\abc");File f3 = new File(d,"c.txt");
File类的常见方法:
1,创建
boolean createNewFile():
在指定位置创建文件,如果创建成功,返回true.如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立就创建文件,而且文件已经存在,会覆盖原文件。
static File createTempFile(String prefix,String suffix):
在默认临时文件目录创建一个空文件,使用给定的前缀与后缀生成其名称。
static File createTempFile(String prefix,String suffix,File directory)
在指定目录创建一个空文件,使用给定的前缀与后缀生成其名称。
2,删除
boolean delete():              删除指定文件,删除成功返回true,删除失败返回false.
void deleteOnExit():         在程序推出时删除指定文件。即使程序中途出现异常导致程序停止,也会删除。

3,判断
boolean exists():              判断文件或目录是否存在。
boolean isFile():               判断是否是文件
boolean isDirectory():      判断是否是目录
boolean isHidden():         判断是否是隐藏文件或目录
boolean isAbsolute():      判断此抽象路径名是否为绝对路径名,无论此文件或文件夹已经被创建。

4,获取信息
String[] list():  
返回指定目录中的所有文件和目录的名称,包含隐藏的。调用list方法的file对象必须是封装了一个目录,并且该目录必须存在,否则将引发NullPointException
String[] list(FilenameFilter filter): 返回指定目录中的经过过滤的所有文件和目录的名称
示例代码:列出d盘下Java目录中(不包含子目录)的所有bmp文件
File dir = new File("d:\\Java");String[] arr = dir.list(new FilenameFilter(){    public boolean accept(File dir,String name)    return name.endsWith(".bmp");});
File[] listFiles():  返回当前目录下所有的文件和目录对象
示例代码:
File dir = new File("c:\\");File[] files = dir.listFiles();for(File f ,files){    System.out.println(f.getName()+"::"+f.getLength());}
static File[] listRoots():  返回系统根目录。
5,比较
int compareTo(): 按字母顺序比较两个抽象路径名。

打印流
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
可以直接操作流和文件,并可指定是否自动刷新流中的数据。
PrintWriter
构造函数可以接收的参数类型:
  •   file对象          File
  •   字符串路径。String 
  •   字节输出流。OutputStream
  •   字符输出流。Writer
PrintStream
构造函数可以接收的参数类型:
  •   file对象          File
  •   字符串路径。String
  •   字节输出流。OutputStream
合并流
SequenceInputStream 对多个流进行合并
SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。  
构造方法:
SequenceInputStream(Enumeration<? extends InputStream> e):
SequenceInputStream(InputStream s1,InputStream s2):
 
代码示例:
文件合并,将1.txt  2.txt  3.txt文件合并成4.txt文件
通过Vector存储流对象,效率低
Vector<InputStream> v = new Vector<InputStream>();v.add(new FileInputStream("c:\\1.txt"));v.add(new FileInputStream("c:\\2.txt"));v.add(new FileInputStream("c:\\3.txt"));Enumeration<InputStream> 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();
通过ArrayList存储流对象
ArrayList<InputStream> al = new ArrayList<InputStream>();al.add(new FileInputStream("c:\\1.txt"));al.add(new FileInputStream("c:\\2.txt"));al.add(new FileInputStream("c:\\3.txt"));final Iterator<InputStream> it = al.iterator();Enumeration<InputStream> en = new Enumeration<InputStream>() {public boolean hasMoreElements() {return it.hasNext();}public InputStream nextElement() {return it.next();}};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();
序列流
被操作的对象需要实现Serialzzable(标记接口)

ObjectOutputStream
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。

ObjectInputStream
ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时可以为应用程序提供对对象图形的持久存储。
ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
 
序列化的作用:
将对象的信息从栈内存中移到硬盘中,实现了对象的持久化存储。
被序列化的对象通常在硬盘中的存储格式:对象名.Object

被transient关键字修饰的非静态成员不能被序列化
静态成员不能被序列化,因为静态成员在方法区,而对象在栈内存中。

当类中自定义了序列化标识:static final long serialVersionUID = 42L; 后
则新的类还能操作曾经被序列化的对象。

管道流
输入输出可以直接进行连接,通过结合线程使用。
  • PipedInputStream
    • 管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。 
  • PipedOutputSteam
    • 可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于 毁坏 状态。
RandomAccessFile
  • RandomAccessFile类不是IO体系中的成员,而是直接继承自Object.但是它是IO包中的成员,因为它具备读和写功能。
  • 内部封装了一个大型数组,而且通过指针对数组的元素进行操作。
  • 可以通过getFilePointer获取指针的位置,同时可以通过seek改变指针的位置。
  • 随机访问文件,自身具备读写的方法。
  • 通过skipBytes(int x),seek(int x)来达到随机访问
  • 读写原理:内部封装了字节输入流和输出流
  • 局限性:RandomAccessFile类只能操作文件,且只有4种模式
  • r: 只读模式,不会创建文件,会读取一个已存在的文件,如果该文件不存在,则会出现异常。
  • rw:读写模式,操作的文件不存在,会自动创建,如果文件存在则不会覆盖。
其他流对象

操作基本数据类型
DataInputStream 与DataOutputStream

操作字节数组
ByteArrayInputStream 与ByteArrayOutputStream
代码示例:
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEF".getBytes());ByteArrayOutputStream bos = new ByteArrayOutputStream();int by = 0;while((by=bis.read())!=-1){    bos.write(by);}
操作字符数组
CharArrayReader与CharArrayWrite

操作字符串
StringReader 与StringWriter