1.序列化与基本类型序列化
1)将类型int 转换成4byte或将其他数据类型转换成byte的过程叫序列化
数据---->n byte
2)反序列化
将n个byte 转换成一个数据的过程
nbyte ---> 数据
3)RandomAccessFile提供基本类型的读写方法,可以将基本类型数据
序列化到文件或者将文件内容反序列化为数据
file类只用于表示文件 目录的信息(名称大小) 不能用于文件内容的访问
File file = new File( "E:\\javaio\\imooc" ); if(!file.exists()) { file.mkdir(); } else { file.delete(); }
一个简单的文件读写
Scanner in = new Scanner( new File( "d:/gmail.txt" ) ); File file = new File( "result.txt" ); BufferedWriter bf = new BufferedWriter( new PrintWriter( file ) ); while ( in.hasNextLine() ) { String str = in.nextLine().split( ":" )[ 1 ]; nums.add( str.length() ); countAppear( str ); }
api
String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
String getName() 返回由此抽象路径名表示的文件或目录的名称
String getParent()返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录 null。
int hashCode() 计算此抽象路径名的哈希码。
boolean isAbsolute() 测试此抽象路径名是否为绝对路径名。
boolean isDirectory() 测试此抽象路径名表示的文件是否是一个目录。
boolean isFile() 测试此抽象路径名表示的文件是否是一个标准文件。
boolean isHidden() 测试此抽象路径名指定的文件是否是一个隐藏文件。
long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
long length() 返回由此抽象路径名表示的文件的长度。
String[] list() 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
String[] list(FilenameFilter filter) 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
File[] listFiles() 返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
File[] listFiles(FileFilter filter) 返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。
遍历所有子目录 构造成File对象
File[] files = dir.listFiles(); if ( files != null && files.length > 0) { for (File file : files ) { if ( file.isDirectory() ) { listDirectory(file); } else { System.out.println(file); } } }
流是指一组有顺序的、 有起点和终点的 字节 集合
二进制字节流: 面向字节的输入和输出。
字符流 :面向字符的输入和输出。是以 Unicode 字符为单位进行读写。
System 类(java.lang)管理标准输入输出流和错误流
public final class System extends Object;
System.out :把输出送到缺省的显示( 通常是显示器)
public static final PrintStream out;
System.in :从标准输入获取输入( 通常是键盘)
public static final InputStream in;
System.err :把错误信息送到缺省的显示。
public static final PrintStream err;
Java 的标准输入输出
注:每当 main 方法被执行时 就自动生成上述三个对象,
所以我们能够直接使用。
Java 中每一种 字节流类 的基本功能都依赖于基本类 InputStream 和 OutputStream 是抽象类不能直接使用
InputStream OutputStream 单位:byte
Reader Writer 单位:char
其他输入输出流都是是他们的子类
---
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader( is );
//BufferedReader是根据“\n”或者“\r”来判断一行的 客户端的close会加一个结束符
BufferedReader bfr = new BufferedReader( isr );
---
Unicode 流 的基本功能依赖于 Reader 和 Writer 这些流用于处理 双字节的Unicode 字符,而不是单字节字符
1)InputStream、OutputStream
InputStream抽象了应用程序读取数据的方式
OutputStream抽象了应用程序写出数据的方式
2)EOF = End 读到-1就读到结尾
3)输入流基本方法
int b = in.read();读取一个字节无符号填充到int低八位.-1是 EOF
in.read( byte[] buf ) 读取数据填充到字节数组
in.read( byte[] buf , int start,int size )
4)输出流基本方法
out.write( int b ) 写出一个byte到流,b的低8位 一个int 32位 4 个字节嘛
out.write( byte[] buf ) 将buf字节数组都写入到流
out.write( byte[] buf , int start , int size )
5)FileInputStream--->具体实现了在文件上读取数据
6)FileOutputStream 实现了向文件中写出byte数据的方法
7)DataOutputStream/DataInputStream
对"流"功能的扩展,可以更加方面的读取int,long,字符等类型数据
DataOutputStream writeInt()/writeDouble()/writeUTF()
8)BufferedInputStream&BufferedOutputStream
这两个流类位IO提供了带缓冲区的操作,一般打开文件进行写入
或读取操作时,都会加上缓冲,这种流模式提高了IO的性能
从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
FileOutputStream--->write()方法相当于一滴一滴地把水“转移”过去
DataOutputStream-->writeXxx()方法会方便一些,相当于一瓢一瓢把水“转移”过去
BufferedOutputStream---> write方法更方便,相当于一飘一瓢先放入桶中,再从桶中倒入到另一个缸中,性能提高
import java.io.*; public class IOUtil { /** * 读取指定文件内容,按照16进制输出到控制台 * 并且每输出10个byte换行 * * @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" ); } // 以16进制输出 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; // in.read( buf, 0, buf.length )是一次性读取这么多的 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(); } } 文件的字节流输出 public class FileOutDemo1 { /** * @param args */ public static void main ( String[] args ) throws IOException { //如果该文件不存在,则直接创建,如果存在,删除后创建 FileOutputStream out = new FileOutputStream( "demo/out.dat" ); out.write( 'A' );//写出了'A'的低八位 41 out.write( 'B' );//写出了'B'的低八位 42 int a = 10;//write只能写八位,那么写一个int需要些4次每次8位 out.write( a >>> 24 ); //00 out.write( a >>> 16 );//00 out.write( a >>> 8 );//00 out.write( a );//0a byte[] gbk = "中国".getBytes( "gbk" ); out.write( gbk ); out.close(); IOUtil.printHex( "demo/out.dat" ); } } //运行结果41 42 00 00 00 0a d6 d0 b9 fa
public class DosDemo { public static void main ( String[] args ) throws IOException { String file = "demo/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( "中国" ); //采用utf-16be编码写出 dos.writeChars( "中国" ); dos.close(); IOUtil.printHex( file ); } } public class DisDemo { public static void main ( String[] args ) throws IOException { // TODO Auto-generated method stub String file = "demo/dos.dat"; IOUtil.printHex( file ); 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(); } } IOUtil.copyFileByByte( new File( "e:\\javaio\\1.mp3" ), new File("e:\\javaio\\2.mp3" ) ); //两万多毫秒 IOUtil.copyFileByBuffer( new File( "e:\\javaio\\1.mp3" ), new File("e:\\javaio\\3.mp3" ) );//一万多毫秒 IOUtil.copyFile( new File( "e:\\javaio\\1.mp3" ), new File("e:\\javaio\\4.mp3" ) );//7毫秒
1) 编码问题
2)认识文本和文本文件
java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)
文件是byte byte byte ...的数据序列
文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果
3)字符流(Reader Writer)---->操作的是文本文本文件
字符的处理,一次处理一个字符
字符的底层任然是基本的字节序列
字符流的基本实现
---------------------------
FileInputStream in = new FileInputStream( "e:\\imoocutf8.txt" ); 这个是读入文件 不能指定编码
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,按照编码处理
InputStreamReader isr = new InputStreamReader( in, "utf-8" );
FileReader/FileWriter 也是不能指定编码
FileReader fr = new FileReader( "e:\\javaio\\imooc.txt" );
---------------------------
public class IsrAndOswDemo { public static void main ( String[] args ) throws IOException { FileInputStream in = new FileInputStream( "e:\\javaio\\imoocutf8.txt" ); InputStreamReader isr = new InputStreamReader( in, "utf-8" );//默认项目的编码,操作的时候,要写文件本身的编码格式 FileOutputStream out = new FileOutputStream( "e:\\javaio\\imoocutf81.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(); } } public class FrAndFwDemo { public static void main ( String[] args ) throws IOException { FileReader fr = new FileReader( "e:\\javaio\\imooc.txt" ); FileWriter fw = new FileWriter( "e:\\javaio\\imooc2.txt" ); //FileWriter fw = new FileWriter("e:\\javaio\\imooc2.txt",true); 追加 char[] buffer = new char[ 2056 ]; int c; while ( ( c = fr.read( buffer, 0, buffer.length ) ) != -1 ) { fw.write( buffer, 0, c ); fw.flush(); } fr.close(); fw.close(); } }---------------------------
字符流的过滤器
BufferedReader ---->readLine 一次读一行
BufferedWriter/PrintWriter ---->写一行
BufferedReader(in1) ---->in1是一个Reader ---->InputStreamReader是最常用的Reader
InputStreamReader(in2) ---->in2是InputStream 比如说FileInputStream
---
3.对象的序列化,反序列化
1)对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化
2)序列化流(ObjectOutputStream),是过滤流----writeObject
反序列化流(ObjectInputStream)---readObject
3)序列化接口(Serializable)
对象必须实现序列化接口 ,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准
public class Student implements Serializable { private String stuno; private String stuname; //不会进行jvm默认的序列化 private transient int stuage; } ... public class ObjectSeriaDemo1 { public static void main ( String[] args ) throws IOException, ClassNotFoundException { String file = "demo3/boj.dat"; ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream( file ) ); Student stu = new Student( "10001", "张三", 20 ); oos.writeObject( stu ); oos.flush(); oos.close(); //上面是序列化 这下面是反序列化 ObjectInputStream ois = new ObjectInputStream( new FileInputStream( file ) ); Student stu2 = ( Student ) ois.readObject(); //Student{stuno='10001', stuname='张三', stuage=20} System.out.println( stu2 ); ois.close(); } }
分析ArrayList源码中序列化和反序列化的问题
5)序列化中 子类和父类构造函数的调用问题
RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,可以访问文件的任意位置
(1)java文件模型
在硬盘上的文件是byte byte byte存储的,是数据的集合
(2)打开文件
有两种模式"rw"(读写) "r"(只读)
RandomAccessFile raf = new RandomeAccessFile(file,"rw")
文件指针,打开文件时指针在开头 pointer = 0;
(3) 写方法
raf.write(int)--->只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
(4)读方法
int b = raf.read()--->读一个字节
(5)文件读写完成以后一定要关闭(Oracle官方说明)
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" ); //指针的位置 0 System.out.println( raf.getFilePointer() );//0 raf.write( 'A' );//只写了一个字节 System.out.println( raf.getFilePointer() );//1 raf.write( 'B' ); int i = 0x7fffffff; //用write方法每次只能写一个字节,如果要把i写进去就得写4次 raf.write( i >>> 24 );//高8位 raf.write( i >>> 16 ); raf.write( i >>> 8 ); raf.write( i ); System.out.println( raf.getFilePointer() );//6 //可以直接写一个int 底层做的就是上面的事情 /*public final void writeInt(int v) throws IOException { write((v >>> 24) & 0xFF); write((v >>> 16) & 0xFF); write((v >>> 8) & 0xFF); write((v >>> 0) & 0xFF); //written += 4; }*/ raf.writeInt( i ); String s = "中"; //gbk里面是-42 -48 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 ); //[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.println( Integer.toHexString( b & 0xff ) + " " ); } raf.close(); } }