Java整理(六)IO

编码问题

String s ="东南大学";
//字符串转换成字节数组
byte[] bytes = s.getBytes();//使用项目默认编码utf-8
byte[] bytes1 = s.getBytes("gbk");//指定编码
for (byteb:bytes){//把字节以16进制方式显示
   
System.out.println(Integer.toHexString(b&0xff));
}
//字节数组转换为字符串
String s_utf8=newString(bytes);
String s_gbk =new String(bytes1,"gbk");
//对应编码解码不正确会乱码
System.out.println(s_utf8);
System.out.println(s_gbk);

gbk编码中文占2字节,英文1字节

utf-8中文占3字节,英文1字节

字节序列变成字符串,需要用对应的编码方式,否则会乱码。

File类

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

import java.io.File;

        File file = new File("./testfiles/");
        if (!file.exists()){//判断文件是否存在
            file.createNewFile();//创建文件
        }
//        file.isDirectory();//判断是否是目录
//        file.isFile();//判断是否是文件
//        file.mkdir();//只建一级目录
//        file.mkdirs();//递归建立多级目录
//        file.delete();//删除文件或目录
        for(String s:file.list()){//列出目录下文件
            System.out.println(s);
        }
        for(File f :file.listFiles()){
            //常用的File对象的API
            System.out.println(f);//file.toString()的内容
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getName());
            System.out.println(f.getParent());
            System.out.println(f.getParentFile().getAbsolutePath());
        }

 

RandomAccessFile类

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

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

File demo = new File("demo");
if(!demo.exists())
   demo.mkdir();
File file = new File(demo,"raf.dat");
if(!file.exists())
   file.createNewFile();

RandomAccessFile raf = new RandomAccessFile(file, "rw");
//指针的位置
System.out.println(raf.getFilePointer());//0

raf.write('A');//只写了一个字节
System.out.println(raf.getFilePointer());//1
raf.write('B');

int i = 0x7fffffff;
//write方法每次只能写一个字节,如果要把i写进去就得写4raf.write(i >>> 24);//8raf.write(i >>> 16);
raf.write(i >>> 8);
raf.write(i);
System.out.println(raf.getFilePointer());//6

//可以直接写一个int
raf.writeInt(i);
System.out.println(raf.getFilePointer());//10

String s = "";
byte[] gbk = s.getBytes("gbk");
raf.write(gbk);
System.out.println(raf.length());//12

//读文件,必须把指针移到头部
raf.seek(0);
//一次性读取,把文件中的内容都读到字节数组中
byte[] buf = new byte[(int)raf.length()];
raf.read(buf);
//输出[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48](十进制)
System.out.println(Arrays.toString(buf));
   for (byte b : buf) {
       //输出41 42 7f ff ff ff 7f ff ff ff d6 d0(十六进制)
   System.out.print(Integer.toHexString(b & 0xff)+" ");
}
   raf.close();

//读取
RandomAccessFile raf = new RandomAccessFile("demo/raf.dat", "r");
raf.seek(2);
int i = 0;
int b = raf.read();//读取到一个字节
System.out.println(raf.getFilePointer());
i = i | (b << 24 );
b = raf.read();
i = i | ( b << 16);
b = raf.read();
i = i | (b << 8 );
b = raf.read();
i = i | b;
System.out.println(Integer.toHexString(i));
raf.seek(2);
i = raf.readInt();
System.out.println(Integer.toHexString(i));
raf.close();

 

IO流

继承Inputstream或Reader的类都有read()方法,用于读取单个字节或者字节数组

继承Outputstream或Writer的类都有writer()方法,用于写单个字节或者字节数组

以上基本方法通常不会用到。

字节流

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

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

数据源包括:字节数组,String对象,文件,“管道”其他种类的流组成的序列,Internet连接等。

InputStream

功能

构造器参数

ByteArrayInputStream

将内存的缓冲区当做InputStream使用

缓冲区

StringBufferInputStream

String转换InputStream

字符串(StringBuffer)

FileInputStream

从文件读取信息

字符串,表文件名

PipedInputStream

用于写入PipedOutputStream

PipedOutputStream

SequenceInputStream

多个InputStream对象转换成单一InputStream

两个InputStream对象或容纳InputStream对象的容器Enumeration

FilterInputStream

抽象类,作为装饰器的接口

BufferedInputStream

DataInputStream

PushbakInputStream

DataInputStream

与DataOutputStream搭配,从流读取基本数据类型(int,char,long)

InputStream

BufferedInputStream

减少写操作

InputStream,可以指定缓冲区大小

PushbackInputStream

能弹出一个字节的缓冲区,可以将读到的最后一个字符回退

InputStream

 

OutputStream

功能

构造器参数

ByteArrayOutputStream

在内存中创建缓冲区

缓冲区初始化尺寸

FileOutputStream

用于将信息写至文件

字符串,表文件名

PipedOutputStream

用于PipedInputStream输出

PipedInputStream

FilterOutputStream

抽象类,作为装饰器

DataOutputStream

PrintStream

BufferedOutputStream

DataOutputStream

与DataInputStream搭配,从流读取基本数据类型(int,char,long)

OutputStream

PrintStream

用于产生格式化输出

DataOutputStream处理数据存储

PrintStream处理显示

OutputStream

BufferedOutputStream

减少写操作

OutputStream,可以指定缓冲区大小

 

InputStream和OutputStream

try{
    byte bWrite[] = {11, 21, 3, 40, 5};
    OutputStream os = new FileOutputStream("test.txt");
    for (int x = 0; x < bWrite.length; x++) {
        os.write(bWrite[x]); // writes the bytes
    }
    os.close();

    InputStream is = new FileInputStream("test.txt");
    int size = is.available();

    for (int i = 0; i < size; i++) {
        System.out.print((char) is.read() + "  ");
    }
    is.close();
} catch (IOException e) {
    System.out.print("Exception");
}

 

ByteArrayOutputStream和ByteArrayInputStream

byte[] bytes={1,2,3,127,-127};
byte[] bytes1=new byte[10];
ByteArrayInputStream bais=new ByteArrayInputStream(bytes);
for (int i=0;i<5;i++){
    System.out.println(bais.read());
}
bais.read(bytes1);//读取到字节数组中
for(int i=0;i<10;i++)
    System.out.println(bytes1[i]);

ByteArrayOutputStream baos=new ByteArrayOutputStream(5);
baos.write(3);
baos.write(4);
bytes1=baos.toByteArray();
for (int i = 0; i < bytes1.length; i++)
    System.out.println(bytes1[i]);

 

FileInputStream和FileOutputStream

这样效率低,仅仅作为学习

File file = new File("C:\\1.pdf");
FileInputStream fin = new FileInputStream("C:\\1.pdf");
FileOutputStream fout = new FileOutputStream("C:\\222.pdf");
for(int i=0;i<file.length();i++) {
   fout.write(fin.read());
}

FileOutputStream out = new FileOutputStream("testfiles/fos.dat");
out.write('A');//写出了'A'的低八位
out.write('B');//写出了'B'的低八位
int a = 0Xabcd1234;//write只能写八位,那么写一个int需要些4次每次8out.write(a >>> 24);
out.write(a >>> 16);
out.write(a >>> 8);
out.write(a);
byte[] gbk = "你好".getBytes("utf8");
out.write(gbk);
out.close();
//此时fos.dat文件中十六进制表示为
//41 42 ab cd 12 34 e4 bd a0 e5 a5 bd

 

DataInputStream和DataOutputStream

String file = "testfiles/dos.dat";
DataOutputStream dos = new DataOutputStream(
        new FileOutputStream(file));
dos.writeInt(10);
dos.writeInt(-10);
dos.writeLong(10l);
dos.writeDouble(10.5);
//采用utf-8编码写出
dos.writeUTF("你好");
dos.close();

DataInputStream dis = new DataInputStream(
        new FileInputStream(file));
int i = dis.readInt();
System.out.println(i);
i = dis.readInt();
System.out.println(i);
long l = dis.readLong();
System.out.println(l);
double d = dis.readDouble();
System.out.println(d);
String s = dis.readUTF();
System.out.println(s);
dis.close();

 

BufferedInputStream和BufferedOutputStream

BufferedInputStream bis = new BufferedInputStream(
        new FileInputStream("testfiles/text1.txt"));
BufferedOutputStream bos = new BufferedOutputStream(
        new FileOutputStream("testfiles/text2.txt"));
byte[] buffer = new byte[1024];
int c ;
while((c = bis.read(buffer,0,buffer.length))!=-1){
    bos.write(buffer,0,c);
    bos.flush();
}
bis.close();
bos.close();

 

字符流

InputStreamReader和OutputStreamWriter

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

OutputStreamWriter完成char流到byte流,按照编码处理。

InputStreamReader isr = new InputStreamReader(
        new FileInputStream("test1.txt"),"utf-8");//使用文件编码读
OutputStreamWriter osw = new OutputStreamWriter(
        new FileOutputStream("test2.txt"),"utf-8");//写入文件的编码,可以为其他编码,如gbk

 

FileInputStream in = new FileInputStream("testfiles/text1.txt");
InputStreamReader isr = new InputStreamReader(in,"utf-8");//默认项目的编码,操作的时候,要写文件本身的编码格式

FileOutputStream out = new FileOutputStream("testfiles/text2.txt");
OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8");
/*int c ;//比较慢
while((c = isr.read())!=-1){
   System.out.print((char)c);
}*/
char[] buffer = new char[8*1024];
int c;
/*批量读取,放入buffer这个字符数组,从第0个位置开始放置,最多放buffer.length个
  返回的是读到的字符的个数
*/
while(( c = isr.read(buffer,0,buffer.length))!=-1){
    String s = new String(buffer,0,c);
    System.out.print(s);
    osw.write(buffer,0,c);
    osw.flush();
}
isr.close();
osw.close();

 

BufferedReader和BufferedWriter

BufferedReader 一次读一行readLine

BufferedWriter 一次写一行write();+ newline();//换行

     //对文件进行读写操作
     BufferedReader br = new BufferedReader(
             new InputStreamReader(
                     new FileInputStream("testfiles/file1"),"utf8"));
     BufferedWriter bw = new BufferedWriter(
             new OutputStreamWriter(
                     new FileOutputStream("testfiles/file2")));

     PrintWriter pw = new PrintWriter("testfiles/file3");
     //可以自动flush,第一个参数则为输出流
     //PrintWriter pw1 = new PrintWriter(outputStream,boolean autoFlush);
     String line ;
     while((line = br.readLine())!=null){
         System.out.println(line);//一次读一行,并不能识别换行
bw.write(line);
//单独写出换行操作
bw.newLine();//换行操作
bw.flush();
         pw.println(line);
         pw.flush();
     }
     br.close();
     bw.close();
     pw.close();

 

FileReader和FileWriter

FileReader fr = new FileReader("testfiles/text1.txt");
FileWriter fw = new FileWriter("testfiles/text2.txt");
//FileWriter fw = new FileWriter("testfiles/text2.txt",true);
char[] buffer = new char[1024];
int c ;
while((c = fr.read(buffer,0,buffer.length))!=-1){
    fw.write(buffer,0,c);
    fw.flush();
}
fr.close();
fw.close();

 

应用(文件拷贝)

栗子参考慕课网(https://www.imooc.com/learn/123)

IOUtil.java

public class IOUtil {
   /**
    * 读取指定文件内容,按照16进制输出到控制台
    * 并且每输出10byte换行
    * @param fileName
    * 单字节读取不适合大文件,大文件效率很低
    */
   public static void printHex(String fileName)throws IOException{
      //把文件作为字节流进行读操作
      FileInputStream in = new FileInputStream(fileName);
      int b ;
      int i = 1;
      while((b = in.read())!=-1){
         if(b <= 0xf){
            //单位数前面补0
            System.out.print("0");
         }
         System.out.print(Integer.toHexString(b)+"  ");
         if(i++%10==0){
            System.out.println();
         }
      }
      in.close();
   }
   /**
    * 批量读取,对大文件而言效率高,也是我们最常用的读文件的方式
    * @param fileName
    * @throws IOException
    */
   public static void printHexByByteArray(String fileName)throws IOException{
      FileInputStream in = new FileInputStream(fileName);
      byte[] buf = new byte[8 * 1024];
      /*in中批量读取字节,放入到buf这个字节数组中,
       * 从第0个位置开始放,最多放buf.length 
       * 返回的是读到的字节的个数
      */
      /*int bytes = in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
      int j = 1; 
      for(int i = 0; i < bytes;i++){
         System.out.print(Integer.toHexString(buf[i] & 0xff)+"  ");
         if(j++%10==0){
            System.out.println();
         }
      }*/
     int bytes = 0;
     int j = 1;
     while((bytes = in.read(buf,0,buf.length))!=-1){
        for(int i = 0 ; i < bytes;i++){
           System.out.print(Integer.toHexString(buf[i] & 0xff)+"  ");
           if(j++%10==0){
              System.out.println();
           }
        }
     }
     in.close();
   }
   /**
    * 文件拷贝,字节批量读取
    * @param srcFile
    * @param destFile
    * @throws IOException
    */
   public static void copyFile(File srcFile,File destFile)throws IOException{
      if(!srcFile.exists()){
         throw new IllegalArgumentException("文件:"+srcFile+"不存在");
      }
      if(!srcFile.isFile()){
         throw new IllegalArgumentException(srcFile+"不是文件");
      }
      FileInputStream in = new FileInputStream(srcFile);
      FileOutputStream out = new FileOutputStream(destFile);
      byte[] buf = new byte[8*1024];
      int b ;
       while((b = in.read(buf,0,buf.length))!=-1){
          out.write(buf,0,b);
          out.flush();//最好加上
       }
       in.close();
       out.close();
      
   }
   /**
    * 进行文件的拷贝,利用带缓冲的字节流
    * @param srcFile
    * @param destFile
    * @throws IOException
    */
   public static void copyFileByBuffer(File srcFile,File destFile)throws IOException{
      if(!srcFile.exists()){
         throw new IllegalArgumentException("文件:"+srcFile+"不存在");
      }
      if(!srcFile.isFile()){
         throw new IllegalArgumentException(srcFile+"不是文件");
      }
      BufferedInputStream bis = new BufferedInputStream(
            new FileInputStream(srcFile));
      BufferedOutputStream bos = new BufferedOutputStream(
            new FileOutputStream(destFile));
      int c ;
      while((c = bis.read())!=-1){
         bos.write(c);
         bos.flush();//刷新缓冲区
      }
      bis.close();
      bos.close();
   }
   /**
    * 单字节,不带缓冲进行文件拷贝
    * @param srcFile
    * @param destFile
    * @throws IOException
    */
   public static void copyFileByByte(File srcFile,File destFile)throws IOException{
      if(!srcFile.exists()){
         throw new IllegalArgumentException("文件:"+srcFile+"不存在");
      }
      if(!srcFile.isFile()){
         throw new IllegalArgumentException(srcFile+"不是文件");
      }
      FileInputStream in = new FileInputStream(srcFile);
      FileOutputStream out = new FileOutputStream(destFile);
      int c ;
      while((c = in.read())!=-1){
         out.write(c);
         out.flush();
      }
      in.close();
      out.close();
   }
}

测试

long start = System.currentTimeMillis();
IOUtil.copyFileByByte(new File("C:\\Users\\SUN\\Desktop\\1.pdf"),
new File("C:\\Users\\SUN\\Desktop\\2.pdf"))//两万多毫秒
long end = System.currentTimeMillis();
System.out.println(end - start );

start = System.currentTimeMillis();
IOUtil.copyFileByBuffer(new File("C:\\Users\\SUN\\Desktop\\1.pdf"),
new File("C:\\Users\\SUN\\Desktop\\3.pdf"));//一万多毫秒*/
end = System.currentTimeMillis();
System.out.println(end - start );

start = System.currentTimeMillis();
IOUtil.copyFile(new File("C:\\Users\\SUN\\Desktop\\1.pdf"),
new File("C:\\Users\\SUN\\Desktop\\3.pdf"));//7毫秒
end = System.currentTimeMillis();
System.out.println(end - start );

 

对象的序列化、反序列化

对象序列化,将object转换为byte序列,反正为反序列化

序列化流ObjectOutputStream——writeObject()

反序列化流ObjectInputStream——readObject()

需要实现序列化接口(Serializable)

注意transient修饰的元素不会进行jvm默认的序列化,可以自己手动进行序列化,但手动序列化和反序列化顺序要一致

如public transientint age;//在序列化时不会写入age值。

对象在反序列化时不需要调用构造方法。

Student.java

public class Student implements Serializable {
    private String stuno;
    private String stuname;
    //该元素不会进行jvm默认的序列化,也可以自己完成这个元素的序列化
    private transient int stuage;
    private transient int stuscore;

    public Student(String stuno, String stuname, int stuage, int stuscore) {
        super();
        this.stuno = stuno;
        this.stuname = stuname;
        this.stuage = stuage;
        this.stuscore = stuscore;
    }

    @Override
    public String toString() {
        return "Student [stuno=" + stuno + ", stuname=" + stuname + ", stuage="
                + stuage + ", stuscore=" + stuscore + "]";
    }

    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        s.defaultWriteObject();//jvm能默认序列化的元素进行序列化操作
        s.writeInt(stuage);//自己完成stuage的序列化
        s.writeInt(stuscore);
    }

    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();//jvm能默认反序列化的元素进行反序列化操作
        this.stuscore = s.readInt();
        this.stuage = s.readInt();//自己完成stuage的反序列化操作
    }
}

 

ObjectSeriaDemo.java

public class ObjectSeriaDemo1 {
   public static void main(String[] args) throws Exception{
      String file = "demo/obj.dat";
      //1.对象的序列化
      ObjectOutputStream oos = new ObjectOutputStream(
            new FileOutputStream(file));
      Student stu = new Student("10002", "豆子", 18,100);
      oos.writeObject(stu);
      oos.flush();
      System.out.println(stu);
      oos.close();

      ObjectInputStream ois = new ObjectInputStream(
            new FileInputStream(file));
      Student stu1 = (Student)ois.readObject();
      System.out.println(stu1);
      ois.close();
   }
}

这里输出为:

Student [stuno=10002, stuname=豆子, stuage=18, stuscore=100]
Student [stuno=10002, stuname=豆子, stuage=100, stuscore=18]

因为手动序列化顺序不一致,所以相反,要注意。

常见的序列化协议:COM、CORBA、XML&SOAP、JSON、Thrift、Protobuf、Avro。

l  保护性地编写readObject方法。readObject方法实际上相当于另一个公有的构造器,如同其他构造器一样,它也要求注意检查参数的有效性,并且在必要的时候对参数进行保护性拷贝。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值