转载

Java I/O输入输出流详解

一、文件的编码

              开发时一定要注意项目默认的编码!!!!!!!!

              文件操作的时候一定要记得关闭!!!!!!!!

       ASCII:美国标准信息交换码,用一个字节的7位可以表示一个字符

       ISO8859-1:拉丁码表,西欧标准字符集,用一个字节的8位表示

       GB2312:中文编码表,用两个字节来表示中文编码

       GBK:中文编码表的升级,融合了更多表示中文文字符号

       GB18030:GBK的取代版本

       BIG-5:同行与港台地区,是繁体字编码方案,俗称“大五码”

       Uicode:国际标准码,融合了多种文字

       UTF-8:是Unicode编码的实现方式,最多用三个字节来表示一个字符

    

       GBK编码     中文占用2个字节,英文占用1个字节

       UTF-8编码   中文占用3个字节,英文占用1个字节

       UTF-16be编码中文占用2个字节,英文占用2个字节

        Java是双字节编码 utf-16be ,即java中每个字符占用两个字节

       

       当你想把一个字节序列变成一个字符串时,字节序列使用什么编码,就需要使用什么编码去显示的调用s.getBytes("字节序列的编码格式");,否则会出现乱码

       文本文件就是字节序列,可以是任意编码的字节序列,但是如果是在中文机器上直接创建文本文件,那么该文本文件只认识 ANSI(本地编码) 编码。如,新建一个TXT文件,内容为联通,打开则会出现乱码,是一种巧合,正好符合了UTF-8编码的规则

   

       Integer.toHexString(Byte);//以十六进制的方式显示

二、File工具类的使用

         1、File类用于表示文件和目录都可以

            File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问

         2、File类的基本API(看手册)

                 构造函数的情况

                创建功能:createNewFile(),mkdir(),mkdirs()

                删除功能:delete()

                重命名功能:renameTo()

                判断功能:isFile(),isDirectory(),exists()等

                获取功能:getName(),getPath(),list()等

                文件过滤器的作用:list(FilenameFilter filter),返回满足指定条件的文件列表

                

            判断参数的时候,可以使用 IllegalArgumentException参数抛出异常

            File.separator设置目录分隔符,Windows、Unix都识别

            相对目录是当前目录,也即在项目的根目录下

         3、遍历目录( 递归 dir.listFiles())

            访问文件系统的时候因为是与JVM以外的资源进行交互,所以,写代码一定要严谨,把各种情况考虑到了

             

三、RandomAccessFile类的使用

       1、 RandomAccessFile  java提供的对文件内容的访问,既可以读,也可以写

          且支持随机访问文件,可以访问文件的任意位置

       2、Java文件模型

             在硬盘上的文件是byte byte byte存储的,是数据的集合

       3、打开文件                
1 RandomAccessFile raf =newRandomAccessFile(file,"rw");//rw,读写,r只读 2 //打开文件时,文件指针在开头,pointer = 0; 3 raf.write(byte);//write方法只会写一个字节,同时直接指针指向下一个位置 4 int b = raf.read();//每次读一个字节,java中每个字符占用两个字节,使用右移8位的方式分次写入 5 raf.seek(指针位置);//移动指针 6 raf.close();//文件读写完一定要关闭,否则可能会有意想不到的后果

在文件下载文件的时候,这种方式有很大的好处,每个线程下载文件的一部分,

          然后再拼接在一起,迅雷就是使用的这种方式,会记录指针的位置

四、字节流(InputStream、OutputStream,两个都是抽象类)

         1、I/O流用来处理设备之间的数据传输

            InputStream抽象了应用程序读取数据的方式

             OutputStream抽象了应用程序写出数据的方式

         2、EOF = End  读到 -1 就读到结尾

         3、输入流的基本方式主要是读

              int b = in.read();//读取一个字节无符号填充到int第八位,-1是EOF

              in.read(byte[] buf);//读入多个字节填充的字节数组

         4、输出流的基本方式主要是写

              out.write(int b);

              out.write(byte[] buf);

         5、FileInputStream具体实现了文件的读取操作

                while((b=in.read())!=-1){读一个文件}

                in.close();//一定要记得关闭流释放系统资源

                批量读取(速度非常快,效率高) vs. 单字节读取(不适合读大文件,效率很低)

          6、FileOutputStream具体实现了向文件中写数据的操作

                是删除文件重新创建,还是在原文件上追加内容, 看构造方法

                自己实现文件的copy操作

                out.flush();

                out.close();

          7、数据输入输出流 DataOutputStream/DataInputStream

                对流功能的扩展,是一个包装类,可以更加方便的读取int,long,字符等类型数据, 本质是使用的一种装饰模式实现

         8、字节缓冲流 BufferedInputStream/BufferedOutputStream

                 为I/O提供了带缓冲区的操作,这种流模式提高了I/O的性能     

                 .write();

                 .flush();//刷新缓冲区,否则写入不到文件中

                 .close();

五、字符流(参考API)

       1、Java为什么引入字符流?

             操作文本时,尤其是包含中文字符等非ASCII码的字符会很不方便

             字符流 = 字节流+编码

             所以,要对 编码问题 非常清楚    

       2、java的文本(char)是16位无符号整数,是字符的Unicode编码(双字节)    

          文件是byte byte byte……的数据序列

          文本文件是文本序列按照某种编码方式序列化为byte的存储

       3、 字符流(Reader Writer)操作的是文本文件

          一次处理一个字符,字符的底层仍然是基本的字节序列

          InputStreamReader 完成byte流 按照编码 解析为char流

          OutputStreamWriter 提供char流 按照编码 解析成byte流

       4、 文件读写流  FileReader、FileWriter

             没法设置编码,必须回到字符流设置编码

       5、 字符流的过滤器BufferedReader、BufferedWriter、PrintWriter

             readLine  可以一次读一行,一次写一行

             可以设置编码,不识别换行,单独写出换行操作

六、 对象的序列化反序列化

         1、将Object对象转换成byte序列,反之叫对象的反序列化

         2、序列化流( ObjectOutputStream ),是过滤流---writeObject()

            反序列化流( ObjectInputStream ),    ----readObject

         3、 序列化接口(Serializable)

            对象必须实现序列化接口 ,才能进行序列化,否则将出现异常

            这个接口没有任何方法,只是一个标准,是标记接口

            

            对象序列化后,如果对再次对类文件修改,那么反序列化的时候就会出问题,那么怎么解决呢?

            需要在类中设置序列版本id,唯一标记,这样无论怎么修改读取的时候都不会再有问题    serialVersionUID

         4、transient关键字

               声明的元素不会进行JVM默认的序列化,也可以自己完成这个元素的序列化

               网络中传输时,并不是所有的元素都是有必要传输的,尤其是要考虑节约网络流量的时候

               在有些情况下,可以帮助我们 提高性能 (ArrayList在数组没有放满的时候, 只把有效元素序列化

         5、序列化中 子类和父类构造函数的调用问题

             父类实现了序列化接口,子类不需要再次实现,就能进行序列化    

             对子类对象进行反序列化操作时,如果其父类没有显示的实现序列化接口,那么其父类的构造函数会被调用

七、输入输出流的一些包装类

       1、打印流

               PrintStream  :字节打印流

               PrintWriter  :字符打印流

               集成了Print()格式化输出方法,可以操作任意类型的数据

       2、标准输入输出流

               System类的in、out字段

               默认输入设备是键盘,输出设备是显示器

八、IO操作过程中异常处理

        

       自己编程要用try-catch-finally包围起来,如果有异常尽量处理,千万不要仅仅是用printStackTrace()打印栈信息,在finally中进行流的关闭(判断引用不为空的话关闭),以确保一定能得到执行

    

 

 

 

 

 

来自为知笔记(Wiz)

正文到此结束
Loading...