[未完成][Mooc]关于IO总结

整个课程的大纲:
1.编码问题.
2.File类的使用
3.RandomAccessFile的使用
4.字节流的使用.
5.字符流的使用.
6.对象的序列化和反序列化.

视频1:文件的编码
Eclipse的一大特点是当你拷贝一个文件到字符编码不一样项目中的时候,再打开会变成乱码,
但是当你拷贝文件中的整个内容到另一个编码不一样的项目中的时候,Eclipse会自动转码成
所在项目中的编码格式.(这样就不会出现乱码.)

中文系统下ANSI编码代表GBK编码.
"联通"和"联"和"联想"分别另存为的编码是不一样的(见我附录的截图)
"联通"和"联"是UTF-8 "联想"是ANSI

程序例子:

 package cn.itcast.io;

 import java.io.UnsupportedEncodingException;

 public class EncodeDemo {
     public static void main(String[] args) throws Exception {
         String s = "慕课ABC";//变成一个字节数组. 一个汉字占用两个字节.英文占用一个字节.
         byte[] byte1 = s.getBytes();//转换成字节序列的作用是项目默认的编码GBK
         for (byte b : byte1) {
             //把字节(转换成了int)以16进制的方式显示
             //System.out.print(Integer.toHexString(b)+" ");
             //输出的是:ffffffc4 ffffffbd ffffffbf ffffffce 41 42 43
             //用十六进制的ff(ox)
             System.out.print(Integer.toHexString(b & 0xff)+" ");
             //输出的是:c4 bd bf ce 41 42 43
         }
         System.out.println();
         byte [] bytes2 = s.getBytes("gbk");
         //gbk编码中文占用两个字节,英文占用一个字节.
         for (byte b : bytes2) {
             System.out.print(Integer.toHexString(b & 0xff)+" ");
             //和上面的输出是一样的:c4 bd bf ce 41 42 43
         }
         System.out.println();

         byte [] bytes3 = s.getBytes("utf-8");
         for (byte b : bytes3) {
             System.out.print(Integer.toHexString(b & 0xff)+" ");
             //输出:e6 85 95 e8 af be 41 42 43
         }
         //可以看出utf-8编码中,中文是三个字节,英文是占用一个字节.
         //java是双字节编码.utf-16be编码
         System.out.println();

         byte [] bytes4 = s.getBytes("utf-16be");
         for (byte b : bytes4) {
             System.out.print(Integer.toHexString(b & 0xff)+" ");
             //输出:61 55 8b fe 0 41 0 42 0 43
             //中文占用两个字节,英文占用两个字节.
         }
         System.out.println();
         //当你的字节序列是某种编码的时候,这个时候想要把字节序列变成字符串.
         //也需要通用这种编码方式.否则会出现乱码.
         String str1 = new String(bytes4);
         //String(byte[] bytes) 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
         System.out.println(str1);
         //输出的是乱码:aU孇 A B C    因为bytes4是用的默认的"gbk"的编码.但是实际上是"utf-16be"的编码
         String str2 = new String(bytes4,"utf-16be");
         System.out.println(str2);//慕课ABC
         //正常输出"慕课ABC"

         /**
          * 文本文件就是字节序列.
          * 可以是任意编码的字节序列
          * 如果我们在中文机器上直接创建文本文件.那么该文本文件值认识ANSI编码.
          * 联通 联 这两个是一个巧合,他们正好符号utf-8的编码规则.
          */

     }
 }

File类
java.io.File类用于表示文件(目录)
File类只用于表示文件(目录)的信息(名称,大小等),不能用于文件内容的访问.
例子2:

 package cn.itcast.io;

 import java.io.File;
 import java.io.IOException;

 public class FileDemo {
     public static void main(String[] args) {
         File file = new File("G:/kxhtest/test");//在构造的时候可以用双斜杠,也可以用反斜杠.
         //也可以用
         File file2 =  new File("e:"+File.separator); //这样可以不管在什么系统中.
         System.out.println(file.exists());//判断文件是否存在.
         if(!file.exists()){
             //file.mkdir();//只能创建一个一级的目录 创建的仅仅是是文件目录,并不是文件.
             //还有一个是创建多级目录的文件.
             file.mkdirs();
         }else{
             file.delete();
         }
         //判断是否是一个目录:返回的是true或者是false
         System.out.println(file.isDirectory());
         //判断是否是一个文件.
         System.out.println(file.isFile());

         File file3 = new File("e:javaio/日记1.txt"); //javaio文件夹必须存在才能创建.不存在不能创建.
         File file4 = new File("e:\\javaio","日记1.txt");
         if(!file3.exists()){
             try {
                 file3.createNewFile();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }else{
             file3.delete();
         }
         System.out.println(file3);//打印的是file的目录.相当于file.toString()的内容
         //e:javaio\日记1.txt
         System.out.println(file3.getAbsolutePath());
         //e:\\javaio\日记1.txt
         System.out.println(file3.getName());
         //日记1.txt
         System.out.println(file3.getParent());
         //e:javaio
         System.out.println(file3.getParentFile().getAbsolutePath());
         //e:\\javaio
     }
 }

File类的使用

 package cn.itcast.io;

 import java.io.File;
 import java.io.IOException;

 /**
  * 列出File的一些常用操作,比如过滤,遍历等操作.
  * @author kongxiaohan
  *
  */
 public class FileUtils {
     /**
      * 列出指定目录下(包括其子目录)中的所有文件
      * @param dir
      * @throws IOException
      */
     public static void listDirectory(File dir) throws IOException{
         if(!dir.exists()){
             throw new IllegalArgumentException("目录"+dir+"不存在");
         }
         if(!dir.isDirectory()){
             throw new IllegalArgumentException(dir+"不是目录");
         }
         /*
         String [] filesnames = dir.list();
         //list()方法用于列出当前目录下的子目录和文件.
         //返回的是字符串数组.直接子的名称,不包含子目录下的内容.
         //所以要判断如果是子目录的话要继续进行遍历取到文件.
         for (String string : filesnames) {
             System.out.println(dir+"\\"+string);
         }
         */

         //如果要遍历子目录下的内容就需要构造成File对象做递归操作.File提供了直接返回File对象的API
         File [] files = dir.listFiles();
         //返回的是直接子目录(文件)的抽象 返回的是File对象.
         if(files != null && files.length>0){
             for (File file : files) {
                 //递归
                 if(file.isDirectory()){
                     listDirectory(file);
                 }else{
                     System.out.println(file);
                 }
             }
         }
     }
 }

 对应输出:
 D:\360Apps\AppDownload\kxh\test.txt
 D:\360Apps\defrag.dat

RandomAccessFile类

RandomAccessFile类是java对文件内容的访问,既可以读文件也可以写文件.
RadomAccessFile可以随机访问文件.可以访问文件的任意位置.

(1)java文件的模型
在硬盘上的文件是byte byte byte 存储的,是数据的集合.
(2)打开文件
有两种模式 一种是"rw"(读写) "r"(只读)
RandomAccessFile raf = new RandomAccessFile(file,"rw");
文件指针,打开文件时指针在开头 pointer = 0;
(3)写方法
raf.write(int)---->只写一个字节(后8位),同时指针指向下一个位置.准备再次写入
(4)读方法
int b = raf.read()---->读一个字节.
(5)文件读写完成之后一定要关闭(Oralce 官方说明 会产生意想不到的错误.)

 package cn.itcast.io;

 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.Arrays;

 /**
  * 迅雷中就是多个线程在同时下载同一个文件,每个线程下载文件的一部分,然后拼接在一起.
  * (拼接的时候一定要记住文件的位置,这个时候用的就是RandomAccessFile)
  * @author kongxiaohan
  *
  */
 public class RafDemo {
     public static void main(String[] args) throws Exception {
         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());
         raf.write('A');//只写了一个字节.只写了后八位
         System.out.println(raf.getFilePointer());
         raf.write('B');
         System.out.println(raf.getFilePointer());

         int i = 0x7fffffff;//这个是最大的int类型的数
         //用write方法,每次只能写一个字节,如果要把i写进去,就要写4次.
         raf.write(i>>>24);//右移了24位,就把高8位留出来了.
         raf.write(i>>>16);//第二个高8位
         raf.write(i>>>8);
         raf.write(i);//高8位
         System.out.println(raf.getFilePointer());

         //可以直接写一个int
         raf.writeInt(i);//直接写应int,其底层就是上面右移的过程,可以看一下源码.
         System.out.println(raf.getFilePointer());
         /*
         write((v >>> 24) & 0xFF);//与上oxFF就是为了去掉前面的0
         write((v >>> 16) & 0xFF);
         write((v >>>  8) & 0xFF);
         write((v >>>  0) & 0xFF);
         */

         String s = "中";//在java的字符串是utf-16be的编码
         byte[] gbk = s.getBytes("gbk");
         raf.write(gbk);
         System.out.println(raf.length());

         //读文件,必须把指针移动到头部
         raf.seek(0);
         //一次性读取.把文件中的内容都读取到字节数组中.
         //上面说到文件再硬盘上本身就是一个byte byte byte的集合. 读取出来还是一个集合.
         byte[] buf = new byte[(int)raf.length()];
         //RandomAccessFile类的length()方法是返回的long类型的.
         raf.read(buf);//这种read是一次性全部读取.
         //也可以一次性读取特定的字节.
         System.out.println(Arrays.toString(buf));

         String s1 = new String(buf,"gbk");
         System.out.println(s1);

         for (byte b : buf) {
             System.out.print(Integer.toHexString(b & 0xff)+" ");
         }
         raf.close();//一定要加上close
     }
 }

字节流之文件输入流FileInputStream
IO流是java做输入输出的基础,可以分为输入流和输出流.
字节流和字符流.(读写文件的单位)
1.字节流
1>InputStream ,OutputStream 这两个类是抽象类.
InputStream抽象了应用程序读取数据的方式.
OutputStream抽象了应用程序写出的数据方式.
2>EOF = End 读取到-1就读到结尾.
3>输入流.(键盘是输入文件,是用来读的.)
所以输入流的方法主要是读:
int b = in.read();读取一个字节.无符号填充到int的低八位.-1是EOF.
in.read(byte[] buf)读取数据填充到字节数组buf.
in.read(byte[] buf,int start,int size)读取数据到字节数组buf.从buf的start位置开始存放size长度的数据.
4>输出流是用来写的操作
out.write(int b) 写出一个byte到流.b的低8位.
out.write(byte[] buf)将buf字节数组都写入到流.
out.write(byte[] buf,int start,int size)字节数组buf从start位置开始写size长度的字节到流.

5>FileInputStream---->具体实现了在文件上读取数据.
例子:

 package cn.itcast.io;

 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;

 public class IOUtils {
     /**
      * 读取指定文件内容,按照16进制输出到控制台.
      * 并且每输出10个byte进行换行.
      * @param fileName
      * @throws IOException
      */
     @SuppressWarnings("resource")
     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){//说明读取到的b是1位的,我们想让其两个两个的输出.
                 //单位数前面补0
                 System.out.print("0");
             }
             System.out.print(Integer.toHexString(b)+" ");
             if(i++ % 10 ==0){// 并且每输出10个byte进行换行.
                 System.out.println();
             }
         }
         in.close();
     }
 }
上一篇:Block 的基本用法


下一篇:RTB撕开黑盒子 Part 1: Datacratic's RTB Algorithms