1、编码问题
package com.imooc_io;public class CodeTest { public static void main(String[] args) throws Exception{ String s = "慕课ABC"; byte[] bytes1 = s.getBytes();//转换成字节序列用的是项目默认的编码 for(byte b:bytes1){ //把字节转换成了int以16进制的方式显示 System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); //gbk编码中文占用两个字节,英文占用一个字节 byte[] bytes2 = s.getBytes("utf-8"); //utf-8编码中文占用3个字节,英文占用一个字节 for(byte b:bytes2){ System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); //java是双字节编码utf-16be byte[] bytes3 = s.getBytes("utf-16be"); //utf-16be编码中文占用2个字节,英文占用2个字节 for(byte b:bytes3){ System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); String str1 = new String(bytes3);//乱码 String str2 = new String(bytes3,"utf-16be"); System.out.println(str1); System.out.println(str2); }}
2、File类
用于表示文件或目录的信息,不能用于文件内容的访问
package com.imooc_io;import java.io.File;import java.io.IOException;public class FileDemo { public static void main(String[] args) { File file = new File("D:\\imooc\\jsp"); System.out.println(file.exists()); if(!file.exists()){ file.mkdir(); }else{ file.delete(); } System.out.println(file.isDirectory()); System.out.println(file.isFile()); File file2 = new File("D:\\imooc\\1.txt"); //File file2 = new File("D:\\imooc","1.txt"); if(!file2.exists()){ try { file2.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ file2.delete(); } //常用的File对象方法 System.out.println(file.getAbsolutePath()); System.out.println(file.getName()); System.out.println(file.getParent()); System.out.println(file.getParentFile().getAbsolutePath()); }}
遍历目录:
package com.imooc_io;import java.io.*;public class FileUtils { /** * 列出指定目录下(包括其子目录)的所有文件 * @throws IllegalAccessException */ public static void listDirectory(File dir)throws IOException, IllegalAccessException{ if(!dir.exists()){ throw new IllegalAccessException("目录:"+dir+"不存在"); }if(!dir.isDirectory()){ throw new IllegalAccessException(dir+"不是目录"); } //直接子的名称,不包含子目录下的文件 /** String[] filenames = dir.list(); for(String string : filenames){ System.out.println(dir+"\\"+string); } */ //如果要遍历子目录下的内容就需要构造File对象做递归操作 File[] files = dir.listFiles();//返回的是直接子目录(文件)的抽象// for(File file:files){// System.out.println(file);// } if(files!=null&&files.length>0){ for(File file:files){ if(file.isDirectory()){ listDirectory(file); }else{ System.out.println(file); } } } }}
3、RandomAcessFile
Java提供的对文件内容的访问,既可以读文件也可以写文件
支持随机访问文件,可以访问文件的任意位置
Java文件模型
在硬盘上的文件是byte存储的,是数据的集合
打开文件
有两种模式"rw","r"
RandomAccessFile raf = new RandomAccessFile(file,"rw");
文件指针,打开文件时在开头pointer = 0;
package com.imooc_io;import java.io.*;import java.lang.reflect.Array;import java.util.Arrays;public class RafDemo { public static void main(String[] args) throws IOException { 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');//只写一个字节 int i = 0x7fffffff;//java最大整数 //如果要把i写进去写4次 raf.write(i>>>24);//高8位 raf.write(i>>>16); raf.write(i>>>8); raf.write(i); System.out.println(raf.getFilePointer()); //可以直接写一个int raf.writeInt(i); //读文件,必须把指针移到头部 raf.seek(0); //一次性读取,把文件的内容都读到字节数组中 byte[] buf = new byte[(int) raf.length()]; raf.read(buf); System.out.println(Arrays.toString(buf)); }}
4、字节流FileInputStream
具体实现了在文件上读取数据
输入流基本方法
int b = in.read();读取一个字节无符号填充到int低8位。-1是EOF结尾的意思
in.read(byte[] buf);读取数据填充到字节数组buf
in.read(byte[] buf ,int start,int size);
输出流基本方法
out.write(int b)
out.write(byte[] buf)
out.write(byte buf , int start,int size);
package com.imooc_io;import java.io.FileInputStream;import java.io.IOException;public class IOUtil { /** * 读取指定文件内容,按照16进制输出到控制台 * 并且没输出10个byte换行 * @throws IOException */ 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"); } //将整型b转换为16进制表示的字符串 System.out.print(Integer.toHexString(b)+" "); if(i++%10==0){ System.out.println(); } } in.close(); } public static void printHexByByteArray(String fileName) throws IOException{ FileInputStream in = new FileInputStream(fileName); byte[] buf = new byte[20*1024]; int bytes = in.read(buf, 0, buf.length); int j = 1; for(int i =0;i
5、字节输出流FileOutputStream
//如果该文件不存在,则直接创建,如果存在,删除后创建
FileOutputStream out = new FileOutputStream("demo/out.dat");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(); }
DataOutputStream/DataIntputStream
对“流”功能的扩展,可以更加方便的读取int, long,字符等类型数据
DataOutputStream:writeInt()/writeDouble()/writeUTF()
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
6、字节缓冲流BufferedInputStream/BufferedOutputStream
这两个流类为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IIO的性能
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(); }
7、字符流
Java的文本(char)是16位无符号整数,是字符的Unicode编码(双字节编码)
文件是byte、byte、byte。。。的数据序列
文本文件是文本(char)序列按照某种编码方案序列化为byte的存储结构
字符流(Reader/Writer):处理文本文本文件
字符的处理,一次处理一个字符
字符的底层任然是基本的字节序列
字符流的基本实现
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,有编码处理
public static void main(String[] args) throws IOException { FileInputStream in =new FileInputStream("D:\\Java open source\\API\\javascript\\JavaScript方法大全.txt"); InputStreamReader isr = new InputStreamReader(in,"UTF-8"); FileOutputStream out = new FileOutputStream("D:\\Java open source\\API\\javascript\\JavaScript方法大全2.txt"); OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8"); // int c;// while((c = isr.read())!=-1){// System.out.print((char)c);// } char[] buf = new char[8*1024]; int c; //批量读取,放入buffer这个字符数组,从第0个位置开始的位置,最多放buf.length //返回的是读到字符的个数 while ((c = isr.read(buf,0,buf.length))!=-1) { String s = new String(buf,0,c); System.out.print(s); osw.write(buf, 0, c); } in.close(); out.close(); isr.close(); osw.close(); }
FileReader/FileWriter没有编码参数,有编码问题时,还是要回归上面方法
字符流的过滤器
BufferedReader --->readLine一次读一行
BufferedWriter/PrintWriter
public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream("D:\\Java open source\\API\\javascript\\1.txt")));// BufferedWriter bw = new BufferedWriter(// new OutputStreamWriter(// new FileOutputStream("D:\\Java open source\\API\\javascript\\2.txt"))); PrintWriter pw = new PrintWriter("D:\\Java open source\\API\\javascript\\3.txt"); 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(); }
8、对象的序列化和反序列化
对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化
序列化流(ObjectOuputStream),是过滤流---WriteObject
反序列化流(ObjectInputStream)---readObject
序列化接口(Serializable)
对象必须实现序列化接口,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准
public class Student implements Serializable{ private static final long serialVersionUID = 1L;public static void main(String[] args) throws IOException{ String file="demo/obj.dat"; //对象序列化 ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(file)); Student stu = new Student("100001","zhangsan","20"); oos.writeObject(stu); oos.flush(); oos.close();
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(file)); Student stu1 = (Student) ois.readObject(); ois.close();}
希望对象能在网络进行传输,在网络进行传输是以字节为单位,需要把对象序列化成字节,所以需要序列化
transient关键字:
private transient int stuage;//该元素不会被jvm默认的序列化,也可以自己完成这个元素序列化
有些元素在网络传输中不需要序列化,如果还序列化则会浪费资源
分析ArrayList的序列化和反序列化源码。
序列化中子父类构造函数的调用问题:
package com.imooc_io;import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.Serializable;public class ObjectserialDemo { public static void main(String[] args) throws IOException, Exception{// ObjectOutputStream oos = new ObjectOutputStream(// new FileOutputStream("demo/obj1.dat"));// Foo2 foo2 = new Foo2();// oos.writeObject(foo2);// oos.flush();// oos.close(); //反序列化是否递归调用父类的构造函数 ObjectInputStream ois = new ObjectInputStream( new FileInputStream("demo/obj1.dat")); Foo2 foo2 = (Foo2) ois.readObject(); //发现没有调用构造函数,只是打印了这个对象 System.out.println(foo2); ois.close(); }}/***一个类实现了序列化接口,那么其子类都可以进行序列化*对子类对象进行反序列化操作时,如果其父类没有实现序列化接口,*那么其父类的构造函数会被调用*序列化了,构造函数不会被调用*/class Foo implements Serializable{ public Foo(){ System.out.println("foo..."); }}class Foo1 extends Foo{ public Foo1(){ System.out.println("foo1..."); }}class Foo2 extends Foo1{ public Foo2(){ System.out.println("foo2..."); }}