Java I/O输入输出流
2015-08-30 16:02
501 查看
编码问题
String s = "Java 教程"; byte[] byte1 = s.getBytes(); //使用默认编码。 byte[] byte2 = s.getBytes("utf-8"); //显示指定编码格式为 utf-8 //把字节(转换成int)以16进制方式显示 // GBK编码 中文占2个字节,英文占1个字节 // UTF-8 编码,中文占用3个字节,英文占用1个字节 // Java 是双字节编码 UTF-16be for( byte b : byte1) { System.out.print(Integer.toHexString(b & 0xff) + " "); }
当你的字节序列是某种编码时,在把字节序列变成字符串时,也需要使用该种编码,否则会乱码。
String str = new String(b,"utf-16be");
文本文件就是字节序列,可以是任意编码的字节序列。
如果在中文机器上直接创建的文本文件,那么文本文件只认识ansi编码。
复制的还是按照原来的编码格式
File 类常用API
Java中,java.io.FIle类用于表示文件(目录),只用于表示文件(目录)的信息(名称、大小),不能用于文件访问。
File file = new File("E:\\java\\javaTest"); // 一个目录 File file2 = new File("E://java//test1.java"); // 一个文件 File file3 = new File("E://java","test2.java") //一个文件 if(!file.exists()) { file.mkdir(); //创建一个目录 file.createNewFile(); //创建一个文件 } else { file.delete(); } if(file.isDirectory()) { } if(file2.isFile()) { } //常用的File对象API file.getAbsolutePath(); file.getName(); file.getParent();
File常用操作:遍历,过滤
//列出指定目录下的目录和文件 String[] filenames = dir.list(); //列出当前目录下的子目录和文件,返回字符串数组。不包含子目录下的内容 // 需要遍历目录下的内容时,就要构造File对象做递归操作。 //File提供了直接返回对象的方法。 File[] files = dir.listFiles(); //返回直接子目录(文件)的对象 if(files != null && files.length > 0) { for (file : files) { if(file.isDirectory()) { //递归 } else { //直接返回 } } }
RandomAccessFile的使用
RandomAcceseeFile 是Java 提供的对文件内容的访问类。既可以读取文件,也可以写文件。并且可以随机访问文件,可以访问文件的任意位置
java 文件模型
在硬盘上的文件是按 字节 存储的,是数据的集合;打开文件
两种模式: “rw”“r”。RandomAccessFile raf = new RandomAccessFile(file, “rw”);
文件指针: 打开文件时指针在开头 pointer = 0;
写方法
raf.write(int) ; //只写一个字节(后8位),同时指针指向下一个字节的位置,准备再次写入读方法
int b = raf.read(); //只读一个字节读写文件后一定要关闭文件,否则可能出现不可预测的错误。
File file = new File("001.dat") { if(!file.exist()) { file.createNewFile(); } RandomAccessFile raf = new RandomAccessFile(file,"rw"); int i = 0x7fffffff; //用write方法没戏只写一个字节。int4个字节,需要写4次 raf.write(i >>> 24); 高8位 raf.write(i >>> 16); raf.write(i >>> 8); //或是用 writeInt 直接写一个int raf.writeInt(i); //write 可以直接写一个字节数组 String s = "中"; byte[] gbk = s.getBytes("gbk"); raf.write(gbk); //写入一个字节数组 //读文件,必须把指针移到头部 raf.seek(0); //一次性读取文件中的所有内容到字节数组中 byte[] buf = new Byte[(int)raf.length()]; raf.read(buf);
IO流(输入流,输出流)
字节流的使用
InputStream、OutputStreamInputStream 抽象了应用程序读取数据的方式
OutputStream 抽象了应用程序写出数据的方式
EOF == end of file 读到-1表示读到文件结尾
输入流基本方法:(注意,键盘是输入流。 从键盘读入数据写到文件中)
int b = in.read(); // 读取一个字节无符号填充int低8位。 -1 是 EOF
`int read(byte[] buf); //读取数据填充到字节数组buf
int read(byte[] buf, int start, int size); //读取数据到字节数组buf,从buf 的start位置开始存放size长度的数据
输出流基本方法
out.write(int b); // 写出一个byte到流中,b的低8位
out.write(byte[] buf); //将buf字节数组写入到流
out.write(byte[] buf, int start, int size); //字节数组buf从start位置开始写size长度的字节到流
FileInputStream 继承InputStream,具体实现了文件上读取数据。
FileInputStream in = new FileInputStream("file");
int b = in.read();
Byte[] buf = new byte[20*1024];
int bytes = in.read(buf,0,buf.length);//从in中批量读取字节,放入到buf这个字节数组中,从第0个位置开始放,最多放buf.length个字节。返回的是读到的字节的个数
FileOutputStream 继承了OutputStream,具体实现了向文件中写出byte数据的方法
//如果文件不存在,直接创建。如果存在,删除后创建
FileOutputStream out = new FileOutputStream(file);
//true 表示 append,在文件后面追加.
//如果文件不存在,直接创建。如果文件存在,直接在文件末尾写入
FileOutputStream out = new FileOutputStream(file,true);
DataInputStream 和 DateOutputStream 数据输入输出流
是对“流”功能的扩展,可以更加方便的读取int,long,字符等类型数据
writeInt()/ writeDouble()/ writeChar()
//有OutputStream嵌套生成
FileOutputStream fout = new FileOutputStream("E:\\001.txt");
DataOutputStream dos = new DataOutputStream(fout);
dos.writeInt(10);
dos.writeUTF("中国");// 采用utf-8编码写出,每个汉字3个字节
dos.writeChars("中国"); //采用utf-16be 编码,每个汉字2个字节
BufferedInputStream & BufferedOutputStream 带缓冲区的字节流操作。
一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能。
FileOutoutStream ---> write()方法:类似一滴一滴的把水“转移”过去 DataOutputStream ---> writeXxx方法:较方便,类似一瓢一瓢的把水‘转移’过去 BufferedOutputStream ---> write() 方法: 更方便,类似把水先一瓢一瓢放到桶中,在从桶中导入水缸中。 FileOutoutStream ---> write(buf,start,size)方法: 速度最快
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();
字符流的使用
认识文本和文本文件
文本: Java 文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)文件: 是按照byte存储的数据序列
文本文件: 是文本(char)序列按照某种编码方案(utf-8,utf-16be, gbk) 序列化为byte的存储结构
字符流输入输出流(Reader, Writer) 操作文本文件
字符的处理: 一次处理一个字符字符的底层仍然是基本的字节序列
字符流的基本实现
InputStreamReader: 完成byte流解析为char流,按照编码解析
OuputStreamWriter: 提供char流发到byte流,按照编码解析
FileInputStream in = new FileInputStram("001.txt"); InputStreamReader isr = new InputStreamReader(in,"gbk"); //默认按照gbk编码 int c = isr.read(); char[] buffer = new char[8 * 1024]; c = isr.read(buffer, 0, buffer.length); //批量读取字符,放入buffer字符数组,从0位置开始放置,最多放置length个,返回读取到的字符个数 String s = new String(buffer,0,c); //把字符存储到字符串中
另外一种实现: FileReader&FileWriter
注意: 没有编码参数,需要设置编码时,就用InputStreamReader&OutputStreamWriter
FileReader fr = new FileReader("001.txt"); FileWriter fw = new FileWriter("002.txt"); //FileWriter fw = new FileWriter("002.txt","true");//文件后面追加 while((int c = fr.read(buffer,0,buffer,length) != -1) { fw.write(buffer,0,c); fw.flush(); } fr.close(); fw.close();
字符流的过滤器 BufferedReader
BufferedReader 除了基本的读取外,可以一次读取一行BufferedWriter/ PrintWriter 可以一次写一行
BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream("001.txt"[,"utf-8"]))); //或是用FileReader() //BufferedReader br = new BufferedWriter(FileReader("001.txt")); BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( new FileInputStream("002.txt"[,"utf-8"])); String line; //一次读取一行,不能识别换行,返回是字符串 while(line = br.readLine() != null) { bw.write(line); //单独写出换行操作 bw.newLine(); //换行操作 bw.flush(); } br.close(); bw.close(); // 可以直接用PrintWriter 代替 BufferedWriter // PrintWriter pw = new PrintWriter("003.txt"); // PrintWriter pw1 = new PrintWriter(outputStream, boolean autoFlush); //自动刷新 // pw.print(line); //输出一行,没有换行 // pw.println(line); // 输出一行,有换行
对象的序列化和反序列化
对象的序列化&反序列化
对象的序列化,就是将Object 转换成byte序列对象的反序列化,就是将byte序列转换成Object
序列化流:ObjectOutputStream, 是过滤流 -> writeObject 方法
反序列化流:ObjectInputStream, -> readObject方法
序列化接口 (Serializable)
对象必须实现序列化接口,才能进行序列化,否则会出现异常;
序列化接口没有任何实现方法,只是一个标准。
ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("001.txt")); ObjectInputStream ois = new ObjectInputStream( new FileInputStream("002.txt")); Student stu = new Student("1001","张三"); // Student 类要实现Serializable 接口,否则出现异常 oos.writeObject(stu); Student stu2 = (Student)ois.readObject(); oos.flush(); oos.close(); ois.close();
关键字: transient
transient 修饰的元素不会进行JVM默认的序列化但是可以自己定义给元素的序列化。
例如在ArrayLis中,底层的数组是不一定会被填满的。
所以ArrayList 自己定义数组元素的序列化和反序列化,这样可以舍去空元素,提高性能。
序列化中子类和父类构造函数的调用
父类实现了序列化接口,其子类都能进行序列化。定义的3个foo类
序列化时递归调用父类构造函数
反序列化操作1
反序列化操作1 结果: 只打印出了对象,没有打印出构造函数调用结果
另外3个类
序列化时会打印3个构造函数。
反序列化时会打印父类的构造函数:
反序列化操作 bar 类
说明 对子类对象进行反序列化操作时,如果其父类没有实现序列化接口,那么其父类的构造函数会被调用。
相关文章推荐
- java输入输出流
- The Java EE 6 Tutorial Finalizing a Servlet
- Spring组件扫描<context:component-scan/>使用详解
- SpringMVC基础-@CookieValue
- java -- 提交乱码汇总
- SpringMVC基础-@RequestHeader
- java中throws和throw的区别和用法
- Java 编程
- java 时间计算
- JAVA String.format 方法使用介绍
- java 时间与字符串之间的转换
- JAVA异常处理
- SpringMVC基础-@RequestParam
- (模板)java文件读写与保留小数
- 在Ubuntu中安装Eclipse与创建桌面快捷方式
- 关于math.random运用的个人体会。
- 深入了解Java虚拟机读书笔记(一)JVM内存区域
- JAVA之JSON生成与解析
- 用Java实现的帧动画效果
- SpringMVC基础-@PathVariable