io学习

来源:互联网 发布:vb登录界面模板下载 编辑:程序博客网 时间:2024/06/05 18:50

IO是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入

根据处理数据类型的不同分为:字符流和字节流

根据数据流向不同分为:输入流和输出流


通过数据流、序列化和文件系统提供系统输入和输出。

Java IO中的四各类:InputStream、OutputStream、Reader、Writer

InputStream:继承自InputStream的流都是用于向程序中输入数据的,且数据单位都是字节(8位)。
OutputStream:继承自OutputStream的流都是程序用于向外输出数据的,且数据单位都是字节(8位)。
Reader:继承自Reader的流都是用于向程序中输入数据的,且数据单位都是字符(16位)。
Writer:继承自Writer的流都是程序用于向外输出数据的,且数据单位都是字符(16位)。
Serializable 类通过实现 java.io.Serializable 接口以启用其序列化功能。
看到下面的类一头雾水

BufferedInputStream

BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。

BufferedOutputStream

该类实现缓冲的输出流。

BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

BufferedWriter

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

ByteArrayInputStream

ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。

ByteArrayOutputStream

此类实现了一个输出流,其中的数据被写入一个 byte 数组。

CharArrayReader

此类实现一个可用作字符输入流的字符缓冲区。

CharArrayWriter

此类实现一个可用作 Writer 的字符缓冲区。

Console

此类包含多个方法,可访问与当前 Java 虚拟机关联的基于字符的控制台设备(如果有)。

DataInputStream

数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。

DataOutputStream

数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。

File

文件和目录路径名的抽象表示形式。

FileDescriptor

文件描述符类的实例用作与基础机器有关的某种结构的不透明句柄,该结构表示开放文件、开放套接字或者字节的另一个源或接收者。

FileInputStream

FileInputStream 从文件系统中的某个文件中获得输入字节。

FileOutputStream

文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。

FilePermission

此类表示对文件和目录的访问。

FileReader

用来读取字符文件的便捷类。

FileWriter

用来写入字符文件的便捷类。

FilterInputStream

FilterInputStream 包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。

FilterOutputStream

此类是过滤输出流的所有类的超类

FilterReader

用于读取已过滤的字符流的抽象类

FilterWriter

用于写入已过滤的字符流的抽象类。

InputStream

此抽象类是表示字节输入流的所有类的超类。

InputStreamReader

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。


字节流(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,字符等类型数据,本质是使用的一种装饰模式实现的
        小例子1

        /*
         * 字节流写入文件,将hello world! 写入到文件f:/test1.txt,以字节流的形式
         */
                String hello=new String("Hello World!");byte[] byteArray=hello.getBytes();File file=new File("f:/test1.txt");OutputStream os=new FileOutputStream(file);os.write(byteArray);                //要关闭               os.close();

  /*小例子2

    *字节流的形式读文件

*/

                File file=new File("f:/test1.txt");byte[] bytefie=new byte[(int)file.length()];InputStream ip=new FileInputStream(file);//才发现最重要的是这句int size=ip.read(bytefie);//这行代码是以字节流的形式读取某文件 .read()这个方法,如果读取已到达文件末尾,则返回 -1。System.out.println(size+":"+new String(bytefie));ip.close();

字符流
       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  可以一次读一行,一次写一行
             可以设置编码,不识别换行,单独写出换行操作

/*

*字符流写文件

*/

        String hello=new String("hello world!");File file=new File("f:/test2.txt");Writer os=new FileWriter(file);os.write(hello);os.close();
/*

*字符流读文件

*/

        Reader re=new FileReader(file);char[] aaa=new char[(int)file.length()];re.read(aaa);System.out.println(new String(aaa));re.close();
/*

RandomAccessFile类的使用

 1、RandomAccessFile java提供的对文件内容的访问,既可以读,也可以写且支持随机访问文件,可以访问文件的任意位置
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();//文件读写完一定要关闭,否则可能会有意想不到的后果
在文件下载文件的时候,这种方式有很大的好处,每个线程下载文件的一部分,然后再拼接在一起,迅雷就是使用的这种方式,会记录指针的位置
小例子1:

*在test1文件末尾追加“爱谁谁!“

RandomAccessFile不属于InputStream和OutputStream类系的,类似于指针,可以指定操作文件的什么位置

.seek( )移动到什么位置,.getFilePointer()获取当前位置

对文件的操作权限

           *r 代表以只读方式打开指定文件
          * rw 以读写方式打开指定文件
          * rws 读写方式打开,并对内容或元数据都同步写入底层存储设备
          * rwd 读写方式打开,对文件内容的更新同步更新至底层存储设备

*/

           RandomAccessFile file = new RandomAccessFile( "f:/test1.txt", "rw");file.seek(file.length());    Long beg=file.getFilePointer();file.write("just do it".getBytes());    Long end=file.getFilePointer();    System.out.println(beg+":"+end);    file.close();

打开文件查看:


/*小例子2

*将”Action should not be lazy”插到just do it前面

*/

               //位置        long points=0;RandomAccessFile file=new RandomAccessFile("f:/test1.txt", "rw");int data=file.read();                //获取要插入的位置              while(data!=-1){         if(data=='j'){         points= file.getFilePointer()-1;          }         data = file.read();}//创建临时的文件夹File tmp=File.createTempFile("tmp", null);//退出时删除          tmp.deleteOnExit();FileOutputStream otmp=new FileOutputStream(tmp);FileInputStream itmp=new FileInputStream(tmp);file.seek(points);byte[] h=new byte[1024*2];//用于保存临时读取的字节数                 int hasRead=0;               //将插入点的后面的内容写入临时文件              while((hasRead=file.read(h))>0){          otmp.write(h, 0, hasRead);                 }               file.seek(points);             //写文件             file.write("Action should not be lazy,".getBytes());             //最后追加临时文件中的内容              while((hasRead=itmp.read(h))>0){          file.write(h,0,hasRead);               }  
结果:

            字节缓冲流BufferedInputStream/BufferedOutputStream
                 为I/O提供了带缓冲区的操作,这种流模式提高了I/O的性能     
                 .write();
                 .flush();//刷新缓冲区,否则写入不到文件中
                 .close();

       /*小例子BufferedInputStream
         * 使用缓冲流读文件
         *        
         */

                File file=new File("f:/test1.txt");byte[] aa=new byte[(int)file.length()];InputStream ip=new BufferedInputStream(new FileInputStream(file),2*1024);int size=ip.read(aa);System.out.println(new String(aa));ip.close();

一些知识参考http://www.cnblogs.com/longqingyang/p/5564839.html

文件编码:

       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("字节序列的编码格式");,否则会出现乱码
       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以外的资源进行交互,所以,写代码一定要严谨,把各种情况考虑到了
 
二、对象的序列化和反序列化
         1、将Object对象转换成byte序列,反之叫对象的反序列化
         2、序列化流(ObjectOutputStream),是过滤流---writeObject()
            反序列化流(ObjectInputStream),    ----readObject
         3、序列化接口(Serializable)
            对象必须实现序列化接口,才能进行序列化,否则将出现异常
            这个接口没有任何方法,只是一个标准,是标记接口
            对象序列化后,如果对再次对类文件修改,那么反序列化的时候就会出问题,那么怎么解决呢?
            需要在类中设置序列版本id,唯一标记,这样无论怎么修改读取的时候都不会再有问题   serialVersionUID
         4、transient关键字     
             Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员, 
      我们不想用serialization机制来保存,为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键
      字transient.transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的
      时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。  声明的元素不
     会进行JVM默认的序列化,也可以自己完成这个元素的序列化网络中传输时,并不是所有的元素都是有必要传输
     的,尤其是要考虑节约网络流量的时候在有些情况下,可以帮助我们提高性能(ArrayList在数组没有放满的时候,
    只把有效元素序列化)

         5、序列化中 子类和父类构造函数的调用问题
             父类实现了序列化接口,子类不需要再次实现,就能进行序列化    
             对子类对象进行反序列化操作时,如果其父类没有显示的实现序列化接口,那么其父类的构造函数会被调用
 
三、输入输出流的一些包装类
       1、打印流
               PrintStream  :字节打印流
               PrintWriter  :字符打印流
               集成了Print()格式化输出方法,可以操作任意类型的数据
       2、标准输入输出流
               System类的in、out字段
               默认输入设备是键盘,输出设备是显示器
               
               标准IO重定向
               System.setIn(InputStream);
               //重定向输出可以将打印到控制台的日志写到文件
               System.setOut(PrintStream);
               System.err(PrintStream);
 
       3、进程控制
              在Java内部执行其他操作系统的程序,并要求控制这些程序的输入输出时
              向OSExecute.command()传递一个command字符串  

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

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






0 0
原创粉丝点击