Java拾遗2:文件传输基础——Java IO流
来源:互联网 发布:js正则表达式数字范围 编辑:程序博客网 时间:2024/06/05 07:05
一.文件的编码
常用编码:
GBK编码:中文2个字节,英文1个字节
UTF-8编码:中文3个字节,英文1个字节
UTF-16BE编码:中文2个字节,英文2个字节,Java是使用的双字节编码就是UTF-16BE编码Java文件模型
在硬盘上的文件是以byte byte byte存储的,是数据的集合。
示例代码如下:
package com.imooc.io;/* * 文件的编码 * gbk编码:中文占2个字节,英文占1个字节 * utf-8编码:中文占3个字节,英文占1个字节 * utf-16be编码:中文占2个字节,英文占2个字节;java是双字节编码:utf-16be编码 */public class EncodeDemo { public static void main(String[] args) throws Exception { String s = "学习JavaIO之编码"; byte[] bytes1 = s.getBytes();//字符串转换成字节序列,用的是项目默认的编码 for(byte b:bytes1){ //把字节转换成int以16进制的方式显示 //byte类型8位,int类型32位,为了避免数据转换错误,通过&0xff将高24位清0,得到低8位 System.out.print(Integer.toHexString(b & 0xff) + " "); } System.out.println(); //utf-8编码:中文占3个字节,英文占1个字节 byte[] bytes2 = s.getBytes("utf-8");//字符串转换成字节序列,用的是指定的utf-8编码 for (byte b : bytes2) { System.out.print(Integer.toHexString(b & 0xff) + " "); } System.out.println(); //gbk编码:中文占2个字节,英文占1个字节 byte[] bytes3 = s.getBytes("gbk"); for (byte b : bytes3) { System.out.print(Integer.toHexString(b & 0xff) + " "); } System.out.println(); //utf-16be编码:中文占2个字节,英文占2个字节 //java是双字节编码:utf-16be编码 byte[] bytes4 = s.getBytes("utf-16be"); for (byte b : bytes4) { System.out.print(Integer.toHexString(b & 0xff) + " "); } System.out.println(); /* * 当你的字节序列是某种编码时,这个时候想把字节序列变成字符串, * 也需要用统一的编码方式,否则会出现乱码 */ String str1 = new String(bytes4);//用项目默认编码 System.out.println(str1); String str2 = new String(bytes4,"utf-16be");//用户指定编码 System.out.println(str2); /* * 文本文件就是字节序列 * 可以是任意编码的字节序列 * 如果我们在中文机器上直接创建文本文件,则该文本文件只认识ANSI编码 */ }}
二.File类
- File类
java.io.File类用于表示文件(或者目录)
File类只用于表示文件(或者目录)的信息(名称、大小等),不能用于文件内容的访问
创建File对象:File file = new File(filepath)
- 常用方法
file.exists() //是否存在 file.mkdir() //创建目录 file.createNewFile() //创建新文件 file.mkdirs() //创建多级目录 file.delete() //删除文件(或者目录) file.isDirectory() //判断是否是个目录 file.isFile() //判断是否是个文件
示例程序如下:
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("C:\\Users\\kai\\Desktop\\imooc"); //是否存在 //System.out.println(file.exists()); if(!file.exists()){ file.mkdir();//file.mkdirs()创建多级目录 } else { file.delete(); } System.out.println(file.isDirectory());//是否是一个目录 System.out.println(file.isFile()); //是否是一个文件 //File file2 = new File("C:\\Users\\kai\\Desktop\\imooc\\日记1.txt"); File file2 = new File("C:\\Users\\kai\\Desktop\\imooc","日记1.txt"); if(!file2.exists()){ try { file2.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } else { file2.delete(); } //常用FILE对象API System.out.println(file); //相当于file.toString() System.out.println(file.getAbsolutePath()); //绝对路径 System.out.println(file.getName()); //当前目录名 System.out.println(file2.getName()); //当前文件名 System.out.println(file.getParent()); //父目录 System.out.println(file2.getParent()); System.out.println(file.getPath()); }}
package com.imooc.io;import java.io.File;import java.io.IOException;/* * 列出File类的一些常用操作,比如过滤,遍历等操作 */public class FileUtils { /* * 列出指定目录下(包含其子目录)的所有文件 */ public static void listDirectory(File dir) throws IOException{ if(!dir.exists()){ throw new IllegalArgumentException("目录:"+dir+"不存在"); } if(!dir.isDirectory()){ throw new IllegalArgumentException(dir+"不是目录"); } /*String[] filenames = dir.list(); //list()方法用于列出当前目录下的子目录和文件,返回字符串数组,只是名称,不包含子目录下一级子目录的内容 for(String string:filenames){ System.out.println(dir+"\\"+string); }*/ //如果要遍历子目录下的的内容就需要构造成File对象,做递归操作,直到得到所有子目录下的文件。 //File提供了直接返回File对象的API:file.listFiles() File[] files = dir.listFiles();//返回的是当前目录下的所有文件或者目录下的文件 if(files!=null && files.length > 0){ for (File file : files) { if(file.isDirectory()){ listDirectory(file); } else { System.out.println(file); } } } }}
三.RandomAcessFile类
RandomAcessFile类
File类只能用于表示文件(或者目录)的信息(名称、大小等),不能用于文件内容的访问,但是RandomAcessFile类则是Java提供的可以对文件内容的访问的类,既可以读文件,也可以写文件,而且支持随机访问文件,可以访问文件的任意位置。RandomAcessFile类应用
(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()
—>读一个字节raf.read(byte[] buf)
—>也可以直接读入一个字节数组buf中
(5)文件读写完成以后一定要关闭(Oracle官方说明)raf.close()
示例程序如下:
package com.imooc.io;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;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");//以读写的方式随机访问文件file System.out.println(raf.getFilePointer());//指针的位置 /* * 写入:以字节方式写入 */ raf.write('A');//只写了一个字节,char的后8位 System.out.println(raf.getFilePointer()); raf.write('B'); int i = 0x7fffffff; //用writ()方法每次只能写一个字节,如果要把i写进去,就需要4次 raf.write(i>>>24); //高8位 raf.write(i>>>16); raf.write(i>>>8); raf.write(i>>>0); System.out.println(raf.getFilePointer()); raf.writeInt(i); //可以直接写一个int String s = "中"; 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);//一次性读取,把文件中的内容都读到字节数组中 System.out.println(Arrays.toString(buf)); for (byte b : buf) { System.out.print(Integer.toHexString(b & 0xff) + " "); //字节(8位)转换成int(32位),为了避免数据转换错误,通过&0xff将高24位清0,取低8位 } /*String s1 = new String(buf,"gbk"); System.out.println(s1);*/ raf.close(); //注意:一定要关闭 }}
四.IO流
IO主要分为字节流和字符流
字节流
(1)InputStream、OutputStream
- InputStream 抽象了应用程序读取数据的方式
- OutputStream抽象了应用程序写出数据的方式
(2)EOF = End 读到-1就读文件结尾(EOF = -1)
(3)输入流基本方法
int b = in.read();
读取一个字节无符号填充到int低八位in.read(byte[] buf);
读取数据到字节数组中in.read(byte[] buf,int start,int size)
(4)输出流基本方法
out.write(int b);
写出一个byte到流:b的低8位out.write(byte[] buf)
将buf字节数组都写入到流out.write(byte[] buf,int start,int size)
(5)FileOutputStream/FileInputStream
- FileInputStream—->实现了在文件中读取数据到流
- FileOutputStream–>实现了向文件中写出byte数据的方法
(6)DataOutputStream/DataInputStream
- 对”流”功能的扩展,可以更加方面的读取int,long,字符等类型数据
如:DataOutputStream的writeInt()/writeDouble()/writeUTF()
(7)BufferedInputStream/BufferedOutputStream
- 这两个流类为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能
- 从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中
(8)对比
- FileOutputStream—>write()方法相当于一滴一滴地把水“转移”过去
- DataOutputStream–>writeXxx()方法会方便一些,相当于一瓢一瓢把水“转移”过去
- BufferedOutputStream—>write方法更方便,相当于一飘一瓢先放入桶中,再从桶中倒入到另一个缸中,性能提高了
字符流
(1)认识文本和文本文件
- java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)
- 文件是byte byte byte …的数据序列
- 文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果
(2)字符流(Reader Writer)
- 操作的是文本文本文件
- 字符的处理,一次处理一个字符
- 字符的底层任然是基本的字节序列
(3)字符流的基本实现
- InputStreamReader/OutputStreamWriter
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,按照编码处理 - FileReader/FileWriter
- BufferedReader/ BufferedWriter/PrintWriter:字符流的过滤器
BufferedReader —->readLine 一次读一行
BufferedWriter/PrintWriter —->写一行
字节流示例程序如下:
package com.imooc.io;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class IOUtil { /* * 读取指定文件的内容,按照16进制输出到控制台 * 每输出10byte换行 */ 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)+" "); //这个不需要&0xff是因为没有转换 if(i++%10 == 0){ System.out.println(); } } in.close(); } public static void printHexByByteArray(String fileName) throws IOException { /* * 从in中批量读取字节,放入字节数组buf中, * 从第0个位置开始放,最多放buf.length个 * 返回的是读到的字节的个数(可能放不满) */ /* 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 < bytes; i++){ System.out.print(Integer.toHexString(buf[i] & 0xff)+" "); if(j++%10==0){ System.out.println(); } } */ FileInputStream in = new FileInputStream(fileName); byte[] buf = new byte[20 * 1024]; 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) + " ");//byte类型8位,int类型32位,为了避免数据转换错误,通过&0xff将高24位清0,得到低8位 if(j++%10==0){ System.out.println(); } } } } //批量读取:copyFile(File srcFile, File destFile)最快 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, buf.length); out.flush();//最好加上 } in.close(); out.close();//一定要记得关闭 } 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(); } 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(); }}
package com.imooc.io;import java.io.DataInputStream;import java.io.FileInputStream;import java.io.IOException;public class DisDemo { public static void main(String[] args) throws IOException{ 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(); }}
package com.imooc.io;import java.io.DataOutputStream;import java.io.FileOutputStream;import java.io.IOException;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); dos.writeUTF("中国");//utf-8 dos.writeChars("中国");//utf-16be dos.close(); IOUtil.printHex(file); }}
字符流示例程序如下:
package com.imooc.io;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;public class IsrAndOswDemo { public static void main(String[] args) throws IOException { FileInputStream in = new FileInputStream("C:\\Users\\kai\\Desktop\\JavaIO\\coreJava\\bin\\file.txt"); InputStreamReader isr = new InputStreamReader(in,"gbk");//默认项目的编码,操作的时候,要补充文件的编码方式 FileOutputStream out = new FileOutputStream("C:\\Users\\kai\\Desktop\\JavaIO\\coreJava\\bin\\fileutf8.txt"); OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8"); /* int c; while((c = isr.read())!= -1){ System.out.print((char)c); }*/ /* * 批量读取,放入buffer这个字符数组,从第0个开始,最多放buffer.length个字符 * 返回的是读到的字节的个数 */ char[] buffer = new char[8*1024]; int c; 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(); }}
package com.imooc.io;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class FrAndFwDemo { public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("C:\\Users\\kai\\Desktop\\JavaIO\\coreJava\\bin\\file.txt");//file.txt为gbk编码方式 FileWriter fw = new FileWriter("C:\\Users\\kai\\Desktop\\JavaIO\\coreJava\\bin\\file1.0.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(); }}
package com.imooc.io;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;public class BrAndBwOrPwDemo { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream("C:\\Users\\kai\\Desktop\\JavaIO\\coreJava\\bin\\fileutf8.txt"))); BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( new FileOutputStream("C:\\Users\\kai\\Desktop\\JavaIO\\coreJava\\bin\\filebw.txt"))); PrintWriter pw = new PrintWriter("C:\\Users\\kai\\Desktop\\JavaIO\\coreJava\\bin\\filepw.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(); }}
五.对象的序列化和反序列化
- 对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化
- 序列化流(ObjectOutputStream),是过滤流—-writeObject
反序列化流(ObjectInputStream) —-readObject 序列化接口(Serializable)
对象必须实现序列化接口 ,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准transient关键字
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException序列化中子类和父类构造函数的调用问题
示例程序如下:
package com.imooc.io;import java.io.Serializable;/* * Student类 * 将Student的对象序列化 */public class Student implements Serializable{ private String stuno; private String stuname; private transient int stuage;//该元素不会进行jvm默认的序列化,但是可以自己进行序列化 public Student() { } public Student(String stuno, String stuname, int stuage) { super(); this.stuno = stuno; this.stuname = stuname; this.stuage = stuage; } public String getStuno() { return stuno; } public void setStuno(String stuno) { this.stuno = stuno; } public String getStuname() { return stuname; } public void setStuname(String stuname) { this.stuname = stuname; } public int getStuage() { return stuage; } public void setStuage(int stuage) { this.stuage = stuage; } @Override public String toString() { return "Student [stuno=" + stuno + ", stuname=" + stuname + ", stuage=" + stuage + "]"; } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化操作 s.writeInt(stuage); } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作 this.stuage = s.readInt();//自己完成stuage的反序列化操作 }}
package com.imooc.io;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class ObjectSeriaDemo1 { public static void main(String[] args) throws IOException, ClassNotFoundException{ String file = "demo/obj.dat"; /* * 1.对象的序列化 */ /*ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(file)); Student stu = new Student("10001","张三",20); oos.writeObject(stu); oos.flush(); oos.close();*/ /* * 2.反序列化 */ ObjectInputStream ois = new ObjectInputStream( new FileInputStream(file)); Student stu = (Student)ois.readObject(); System.out.println(stu); ois.close(); }}
package com.imooc.io;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class ObjectSeriaDemo2 { public static void main(String[] args) throws IOException, ClassNotFoundException { /*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();*/ /*ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("demo/obj1.dat")); Bar2 bar2 = new Bar2(); oos.writeObject(bar2); oos.flush(); oos.close();*/ ObjectInputStream ois = new ObjectInputStream( new FileInputStream("demo/obj1.dat")); Bar2 bar2 = (Bar2)ois.readObject(); System.out.println(bar2); 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..."); }}class Bar{ public Bar(){ System.out.println("bar"); }}class Bar1 extends Bar{ public Bar1(){ System.out.println("bar1.."); }}class Bar2 extends Bar1 implements Serializable{ public Bar2(){ System.out.println("bar2..."); }}
参考资料
- 1.Cedar,文件传输基础——Java IO流
水平有限,错误和不妥之处请指出,谢谢~
- Java拾遗2:文件传输基础——Java IO流
- 文件传输基础——Java IO流
- 文件传输基础——Java IO流
- 文件传输基础——Java IO流
- 文件传输基础——Java IO流
- 文件传输基础——Java IO流
- 文件传输基础----Java IO流
- 文件传输基础——Java IO流笔记
- 文件传输基础—Java IO流 FileInputStream 的运用
- Java拾遗------IO流
- 《文件传输基础----Java IO流---《一》》
- 《文件传输基础----Java IO流---《二》》
- 《文件传输基础----Java IO流---《三》》
- Java IO 流(文件传输基础)
- 文件传输基础(Java IO流)--慕课网笔记
- 黑马程序员——java基础拾遗之IO流(一) 常用类及方法
- Java学习之文件传输基础---Java IO流
- 慕课JAVA之文件传输基础----JAVA IO流
- linux 中shell编程中的test用法
- 马拉松式学习与技术人员的成长性
- hibernate文件配置出现Repeated column in mapping for entity的Mapping异常处理
- LeetCode:Best Time to Buy and Sell Stock
- Codeforces Round #406 (Div. 1) C. Till I Collapse(主席树)
- Java拾遗2:文件传输基础——Java IO流
- 《30天自制操作系统》学习笔记Day1
- Immutable bitmap crash error
- Android搭建HTTP服务,作为MediaPlayer的播放源来播放音频
- 2017湖南多校第五场-A(1043): Biorhythms
- 正则匹配之匹配网页img
- java xml dom4j 创建 修改 解析
- 右键新建没有Word怎么办?右键新建添加Word方法!
- int android.support.v7.widget.RecyclerView$ViewHolder.mItemViewType' on a null.....