JavaSE学习笔记--IO流和File

时间:2022-10-26 21:36:26

学习日志:

 

字符流:(JDK1.1 )
Reader:
 FileReader extends InputStreamReader: 专门用来操作文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要想自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。

  FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream。
 常用的构造方法:FileReader(String name);
    FileReader(File file);
  其本身只有构造方法,其他的方法全部是继承于父类得到。
 int read()方法有两种读取的方式,一种是一次读取一个字符,读到结尾返回-1;第二种读取方式:read(char[]),其返回值是读取到的个数,读到结尾返回-1;通常要和具有长度限制的写出操作配合使用。如:write(String str, int off, int len)
 
Writer:
 FileWriter extends OutputStreamWriter:  用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。
  文件是否可用或是否可以被创建取决于底层平台。特别是某些平台一次只允许一个 FileWriter(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。
  其本身只有构造方法,其他的方法全部是继承于父类得到。
  FileWriter 用于写入字符流。要写入原始字节流,请考虑使用 FileOutputStream。
   
  其writer()方法具有覆盖的作用,要想不被覆盖需要使用带追加的方式(true)的构造方法来创建字符写出流对象。当有多次写入时,需要每写一次flush()一次。


注意:FileReader和FileWriter在创建对象/流的读与写 都会抛出异常,需要try{} catch(){}捕获。
 使用完流时,需要在finally中释放资源,当含有多个需要释放的资源时,先判断是否是null,然后,逐个嵌套try(){} catch(){}; (可以参见我写的例子)。
 来关闭底层的资源,注意在关闭前还要判断对象的引用是否为空,否则会报出空指针异常。close()具有两个功能,flush()和close。
 关于抛出的消息,要么写出异常日志,如上;要么抛出Runtime异常(throw new RuntimeExeption("写入失败");//企业级编程使用这种方式) 

 BufferedWriter:  这个类是将缓冲区的技术进行了对象的封装。
  将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
  可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
  该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性 line.separator 定义(该方法底层是调用了write(lineSeparator);)。并非所有平台都使用新行符 ('\n') 来终止各行。因此调用此方法来终止每个输出行要优于直接写入新行符。

  通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,

   PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
   将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。
  在使用此类循环写入的时候,没写写入一行数据后要刷新和换一行。
 
 BufferedReader:  从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

  可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

  通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如,

   BufferedReader in = new BufferedReader(new FileReader("foo.in"));
   将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
  通过用合适的 BufferedReader 替代每个 DataInputStream,可以对将 DataInputStream 用于文字输入的程序进行本地化。
  
   关于String readLine()方法,如果已到达流末尾,则返回 null 。
  其子类中有一个非常有用的一个类 LineNumberReader ,这个内容有一个getLineNumber() 方法来输出行号。


装饰设计模式:
 
 当对类的功能进行增强时,可称之为对该类的装饰。
 同时它的出现具备灵活性。
 如:BufferedReader 中有readLine();  BufferedWriter中的 newLine();

 其内部实现原理:就是将需要增强的那个类作为该装饰类中的一个private成员变量,并通过构造函数的形式来初始化需要被装饰的类的对象,这样这个装饰类内部就具备了该类的所有的方法了。

装饰和继承的区别:
装饰设计模式是一种解决给类提供增强型功能的这类问题的思想,是该类问题的有效解决方案。它相对与继承的有点在于不占用继承的位置。在java中因为不支持多继承,所以在java中extends的位置是很宝贵的。
 
装饰设计模式是一种解决某一类问题的思想。该类问题的有效解决方案。
 解决给类提供增强型功能的问题。
继承:是面向对象的特征之一。

字节流:(JDK1.0 )
OutputStream :
 FileOutputStream : FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter。
     注意:字节流的写入方法,直接将数据写到了目的地,无需flush().因为该对象中不存在缓存区。但是仍然要释放资源。

InputStream : 
 FileOutputStream : FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。


BufferedInputStream
BufferedOutputStream

转换流:是将字节流转换成字符流,来使用字符流的方法。如:读取一行(使用BufferedReader装饰一下),这就是转换流的由来。
  这样以来就可以解决从键盘录入一行,一行一行的读取的操作。
包括:
InputStreamReader
 |--FileReader (子类同样继承了父类的编码表的机制,但是与父类的区别在于"固定使用了平台默认的编码表(简体中文XP系统是GBK)",而父类可以自定义指定编码表)
OutputStreamWriter
 |--FileWriter(同上 FileReader)

 
转换流其实就是将字节流和编码表相结合。将字节流中的字节数据,去查了具体的编码表。
所以转换流才可以获取一个中文字符。

那么转换流的子类用于操作文件的对象FileReader 就直接使用父类的具有转换功能的read方法。就可以一次读一个字符。

总体的框架:
字符流
 |--Reader
  |--InputStreamReader(转换流)
   |--FileReader  
  |--BufferedReader
   |--LineNumberReader
 |--Writer
  |--OutputStreamWriter(转换流)
   |--FileWriter
  |--BufferedWriter

 

File 类:应为流只能用于操作文件的数据,用于操作文件的属性只能通过File类的对象来操作文件或文件夹。
  构造方法摘要 :
  
    根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
  File(String pathname)
   通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
  
    根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
  
 分隔符:
  名称分隔符(":"或";"): static String separator (静态的字段) //使用方法 File.separater
   
  路径分隔符("\\"或"/"): public static final char pathSeparatorChar //使用方法 File.separater
  
 File
  |--构造函数
   |--File(File parent, String child)
   |--File(String pathname)
   |--File(String parent, String child)
  |--创建:
   |--创建文件:createNewFile();createTempFile((String prefix, String suffix);
   |--创建单个目录:mkdir()
   |--创建多级目录:mkdirs()
  |--判断
   |--isDirectory()
   |--isAbsolute()
   |--isFile()
   |--isHidden()
   |--exists()
  |--删除
   |--delete()
   |--deleteOnExit()
  |--获取   
   |--listRoots()
   |--list()
   |--listFiles()

    |--getAbsolutePath()
    |--getPath()
    |--getParent()
    |--getName()
  |--重命名
   |--f.renameTo(f1):将f的文件名改成f1的文件名(剪切+复制)
 
 字符的编码:
  "联通"的问题:在使用gbk写入记事本的时候(编码的过程),
  utf-8对字节都加了一个表示头的信息(头特征码),这决定解码的采用的码表。正是因为联通的二进制的数据正好符合了utf-8的编码,所以解码时查utf-8的编码了。

 

打印流:(能操作目的,不能操作源;可以直接操作文件;可以打印任意数据类型)
 PrintStream :在启动自动刷新时,此类只有使用了带换行的打印输出才可以刷新。如:println、printf(注意不是print)或format三种。
 PrintWriter :建议在需要写入字符而不是字节时使用此类。

管道流:(提供读和写(和打印流不同),读和写不能存在依赖性,所有读和写要同时进行)
 读取和写入流进行"连接",但是需要被多线程操作,因为read方法是阻塞式方法。
 容易引发死锁。
 
 PipedInputStream
 PipedOutputStream

序列流:表示其他输入流的逻辑串联。
SequenceInputStream
原理:1,要获取Enumeration的序列对象,通过Vector的elements方法。
  2,将Enumeration的对象作为SequenceInputStream的参数传入。
  3,定义一个文件输出字节流
  4,将SequenceInputStream中的数据循环写入到文件输出的那个字节流中
  5,关闭用到的流资源。


Properties
Hashtable
 |--Properties
 键与值都是String类型的,主要用于配置文件的永久存储。

RandomAccessFile:随机访问文件


特点:
1,随机访问文件,自身具备读和取的方法。
2,内部封装了一个大的byte类型的数组,这就是说该对象操作的数据是字节数据。
 说明其中封装了字节的读取流和写入流。可以使用内部的指针对这个数组进行数据的操作。
3,提供了getPoint方法获取指针的位置。
 还提供了seek方法设置指针的位置。
4,通过该对象的构造函数可以得知,该对象只能操作文件。也就是源和目的都是文件。
  并通过构造函数的另一个参数来确定访问方式。
  该变量只能接收四个值。
  r:只读 ,rw:读写, rws, rwd。
5,该对象中的方法可以操作基本数据类型。
6,注意被操作的额外年间数据,希望有规律。这样可以通过数据的整数倍来控制指针的偏移。
 对数据进行操作,达到,随机访问的操作效果。

应用:可以用于多线程对大数据的同时写入。只要给每一个线程分配起始索引位,就可以完成多线程随机写入。提高效率。
其write(65)的方法只能取出整数的一个字节。所以得用writeInt(65)方法写出。

对象的存储流:
ObjectInputStream
ObjectOutputStream
对象的持久化存储。专门用于操作对象的流。
肯定封装了操作对象的方法。
写入对象:
ObjectOutputStream oos = new ObjectOutputStream(new FileOutStream("obj.txt"));
oos.writeObject(new Person("lisi",23));
如果一个对象要被写入,必须具备序列化的功能。也就是说要实现Serializable接口(标记接口)。

读取对象:
ObjectInputStream ois = new ObjectInputStream("obj.txt");
Person p = (Person)ois.readObjet();  //CassNotFoundException
注意对象中的静态数据不能被持久化,因为不再堆内存中。如果想将非静态的数据不被持久化,就可以使用transient修饰即可。

DataStream流:
只操作基本数据类型:
DataInputStream
DataOutputStream
这个流中有一个特有的方法:
writeUTF(String str) : 与及其无关方式使用UTF-8修改编码将一个字符串写入基础输出流。
如果使用此方法写入的话,只能使用readUTF()来读取。一个汉字占四个字节。

ByteArrayInputStream
ByteArrayOutputStream
操作数组流对象。它对应的设备就是内存。无需close()资源,因为它不掉用底层资源。