java io流详解

一、文件的编码

              开发时一定要注意项目默认的编码!!!!!!!!
              文件操作的时候一定要记得关闭!!!!!!!!
       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();//文件读写完一定要关闭,否则可能会有意想不到的后果
在文件下载文件的时候,这种方式有很大的好处,每个线程下载文件的一部分,
          然后再拼接在一起,迅雷就是使用的这种方式,会记录指针的位置
       eg:
package  com.my_demo;
 
import  java.io.File;
import  java.io.IOException;
import  java.io.RandomAccessFile;
import  java.util.Arrays;
 
public  class  RafDemo {
 
     
 
     public  static  void  main(String[] args)  throws  IOException{
         File demo =  new  File( "demo" );  // 创建一个文件
         if (!demo.exists()) //如果文件不存在,创建到绝对目录下
             
         {
             demo.mkdirs(); //这是个父目录
         }
         File file =  new  File(demo,  "dat.txt" );
         if (!file.exists()){
             file.createNewFile(); //在demo目录下创建了文件
         }
         
       //  RandomAccessFile raf = new RandomAccessFile(file, "rw");
         RandomAccessFile raf =  new  RandomAccessFile( "dat.txt" "rw" ); //读写方式
         //看一下初始时的指针位置
           System.out.println(raf.getFilePointer());
         
         //往里写一个字节后看看指针的位置
            raf.write( 'c' );  //写了一个字节,它的后八位
            //看一下此时的指针位置
            System.out.println(raf.getFilePointer());
           /**
            * 用writechar()方法时会写入两个字节
            */
//           raf.writeChar('c');
            
            //写入一个int
            int  i =  0x7fffffff ; //最大的整型
            raf.write(i>>> 24 ); //写进去高八位
            raf.write(i>>> 16 );
            raf.write(i>>> 8 );
            raf.write(i);  //Java底层的运行机制
          //看一下此时的指针位置
            System.out.println(raf.getFilePointer());
            
            String s = "中" ;
            byte [] gbk = s.getBytes( "gbk" );
            raf.write(gbk);
            System.out.println(raf.length());
            
            
           //读文件,必须把指针移到头部
            raf.seek( 0 );
            //一次性读取,把文件中的内容都读写到字节数组中
            byte [] buf =  new  byte [( int )raf.length()];
            raf.read(buf);
            
            System.out.println(Arrays.toString(buf));
            //最后必须关闭
            raf.close();
     }
     
        
}

四、字节流(InputStream、OutputStream,两个都是抽象类)
         1、I/O流用来处理设备之间的数据传输
            InputStream抽象了应用程序读取数据的方式
            OutputStream抽象了应用程序写出数据的方式
import java.io.*;
class Test{
    public static void main(String args[]){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        byte[] buffer = new byte[100];
        int temp = 0;
        try{
            fis = new FileInputStream("D:/wenhao/src/from.txt");
            fos = new FileOutputStream("D:/wenhao/src/to.txt");
            while(true){
                temp = fis.read(buffer,0,buffer.length);
                if(temp == -1){
                    break;
                }
                fos.write(buffer,0,temp);
            }        
        }
        catch(Exception e){
            System.out.println(e);
        }
        finally{
            try{
                fis.close();
                fos.close();
            }
            catch(Exception e2){
                System.out.println(e2);
            }
        }

    }
}


         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,字符等类型数据,本质是使用的一种装饰模式实现的
package PipedDemo;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataOutputStreamDemo {

	/**
	 * @param args
	 * @throws IOException 
	 * 
	 * DataOutputStream & DataInputStream 用于操作基本数据类型
	 *  
	 * ByteArrayInputStream   &  ByteArrayOutputStream 用于操作字节数组。
	 *  
	 * CharArrayReader  &   CharArrayWriter  用于操作字符数组
	 *  
	 * StringReader  &  StringWriter  用于操作字符串。
	 * 
	 */
	public static void main(String[] args) throws IOException {
		
		writeDemo();
		readDemo();
			
	}

	public static void readDemo() throws IOException {
		DataInputStream dos = new DataInputStream(new FileInputStream("data.txt"));
		String s = dos.readUTF();
		System.out.println(s);
		
	}

	public static void writeDemo() throws IOException {
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
		dos.writeUTF("你好啊");//UTF-8修改版
		
		
	}

}



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


package com.pocketdigi;
 
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main {
 
	public static void main(String[] args) throws IOException {
		File f = new File("d:/a.txt");
		FileOutputStream fos = new FileOutputStream(f);
		// 构建FileOutputStream对象,文件不存在会自动新建
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		bos.write("1我是中文".getBytes());
		bos.close();
		// 关闭输出流,写入数据,如果下面还要写用flush();
		// 因为是BufferOutputStream链接到FileOutputStream,只需关闭尾端的流
		// 所以不需要关闭FileOutputStream;
		FileInputStream fis = new FileInputStream(f);
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedReader reader = new BufferedReader (new InputStreamReader(bis));
		//之所以用BufferedReader,而不是直接用BufferedInputStream读取,是因为BufferedInputStream是InputStream的间接子类,
		//InputStream的read方法读取的是一个byte,而一个中文占两个byte,所以可能会出现读到半个汉字的情况,就是乱码.
		//BufferedReader继承自Reader,该类的read方法读取的是char,所以无论如何不会出现读个半个汉字的.
        StringBuffer result = new StringBuffer();
        while (reader.ready()) {
            result.append((char)reader.read());
        }
		System.out.println(result.toString());
		reader.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  可以一次读一行,一次写一行
             可以设置编码,不识别换行,单独写出换行操作
 
import java.io.*; 

/** 
* 字符流测试 
* 
* @author leizhimin 2008-8-27 22:16:44 
*/ 
public class TestIOStream { 
    public static void main(String[] args) { 
        testReaderWriter(); 
        testLineNumberReader(); 
    } 

    /** 
     * 带缓冲的字符流 
     */ 
    public static void testReaderWriter() { 
        int bufsize = 25; 
        try { 
            BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("C:\\x.txt"))); 
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File("C:\\xb.txt"))); 

            char buf[] = new char[bufsize];     //字符缓冲区 
            while (bufferedReader.read(buf) != -1) { 
                bufferedWriter.write(buf); 
            } 
            bufferedWriter.flush(); 
            bufferedReader.close(); 
            bufferedWriter.close(); 

        } catch (FileNotFoundException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 

    /** 
     * 按行读取的字符流 
     */ 
    public static void testLineNumberReader() { 
        try { 
            LineNumberReader lineNumberReader = new LineNumberReader(new BufferedReader(new FileReader(new File("C:\\x.txt")))); 

            String lineString;      //行字符串变量 
            int x = 0;              //行号 
            while ((lineString = lineNumberReader.readLine()) != null) { 
                x++; 
                System.out.println("行号:" + x + " >>>" + lineString); 
            } 
            lineNumberReader.close(); 
        } catch (FileNotFoundException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    } 
}
六、对象的序列化和反序列化
         1、将Object对象转换成byte序列,反之叫对象的反序列化
         2、序列化流(ObjectOutputStream),是过滤流---writeObject()
            反序列化流(ObjectInputStream),    ----readObject
         3、序列化接口(Serializable)
            对象必须实现序列化接口,才能进行序列化,否则将出现异常
            这个接口没有任何方法,只是一个标准,是标记接口
            
            对象序列化后,如果对再次对类文件修改,那么反序列化的时候就会出问题,那么怎么解决呢?
            需要在类中设置序列版本id,唯一标记,这样无论怎么修改读取的时候都不会再有问题   serialVersionUID

          4、transient关键字

               声明的元素不会进行JVM默认的序列化,也可以自己完成这个元素的序列化
               网络中传输时,并不是所有的元素都是有必要传输的,尤其是要考虑节约网络流量的时候
               在有些情况下,可以帮助我们提高性能(ArrayList在数组没有放满的时候,只把有效元素序列化)
         5、序列化中 子类和父类构造函数的调用问题
             父类实现了序列化接口,子类不需要再次实现,就能进行序列化    
             对子类对象进行反序列化操作时,如果其父类没有显示的实现序列化接口,那么其父类的构造函数会被调用
         eg: http://blog.csdn.net/siwujidan0125/article/details/43731217

七、输入输出流的一些包装类
       1、打印流
               PrintStream  :字节打印流
               PrintWriter  :字符打印流
               集成了Print()格式化输出方法,可以操作任意类型的数据
       2、标准输入输出流
               System类的in、out字段
               默认输入设备是键盘,输出设备是显示器
               
               标准IO重定向
               System.setIn(InputStream);
               //重定向输出可以将打印到控制台的日志写到文件
               System.setOut(PrintStream);
               System.err(PrintStream);
 
       3、进程控制
              在Java内部执行其他操作系统的程序,并要求控制这些程序的输入输出时
              向OSExecute.command()传递一个command字符串   
Process process = new ProcessBuilder(command.split(" ")).start();

OSExecute.command("javap test");

//javap是java的一个反编译程序

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

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值