首先看一下常用的几种编码方式
public class EncodeDemo { public static void main(String[] agrs)throws IOException { String s="中国ABC"; byte[] byte1=s.getBytes(); //默认采用项目的UTF-8编码 byte[] byte2=s.getBytes("GBK");//显示指定编码方式为GBK byte[] byte3=s.getBytes("UTF-16be"); for(byte b:byte1) { /** * 把字节转换成int以十六进制的方式显示 * 默认采用项目的编码,此处使用UTF-8,得到的结果为e4 b8 ad e5 9b bd 41 42 43 *可见采用utf-8编码,中文占用三个字节,英文占用一个字节 */ System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); for(byte b:byte2) { /** * 把字节转换成int以十六进制的方式显示,高位三个字节补0 * 显示指定编码方式为GBK,,得到的结果为d6 d0 b9 fa 41 42 43 * 可见采用GBK编码,中文占用三个字节,英文占用一个字节 */ System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); for(byte b:byte3) { /** * java是双字节编码utf-16be * 把字节转换成int以十六进制的方式显示,高位三个字节补0 * 显示指定编码方式为UTF-16be,得到的结果为4e 2d 56 fd 0 41 0 42 0 43 * 可见采用UTF-16be编码,中文占用两个字节,英文也占用两个字节 */ System.out.print(Integer.toHexString(b & 0xff)+" "); } System.out.println(); /* * 字节数组转换成字符串,必须与之前的转换采用相同的编码方式,不然会出现乱码 */ String s1 = new String(byte1); System.out.println(s1); //中国ABC,采用默认的项目编码格式 String s2 = new String(byte2); System.out.println(s2);//�й� 出现乱码,因为byte2用的是GBK编码,转换成字符串时用得默认的UTF-8 String s3 = new String(byte2,"GBK"); System.out.println(s3);//中国ABC ,显示指定GBK编码方式,便不会出现乱码 } }
File类的使用:
java.io.File类用于表示文件或目录,它只用于表示文件或目录的信息(名称,大小等),不能用于文件内容的访问
public class FileDemo { public static void main(String[] args) { /* * 了解几种常用的构造函数 */ File file = new File("F:\\开心");//注意:路径要使用双斜杠或者反斜杠 System.out.println(file); File file2 = new File("F:\\开心","开心1.txt"); File file3 = new File(file2,"开心2.txt"); if(!file.exists()) { /* * 如果目录不存在,则创建目录,mkdirs()可用于创建多级目录 * file.createNewFile()用于创建文件 */ file.mkdir(); } else { file.delete(); } /* * File类的几种常用API */ System.out.println(file.isFile()); System.out.println(file.isDirectory()); System.out.println(file); //打印文件的路径 System.out.println(file.getAbsolutePath());//同样打印文件的完整路径 System.out.println(file.getName());//打印文件或目录的名字 System.out.println(file.getParent());//打印文件或目录的父目录 System.out.println(file.getParentFile()); } }
包装对对文件或目录的几种常用操作,如过滤,遍历等
/<span style="font-family: Arial, Helvetica, sans-serif;">/包装File的一些常用操作,如过滤,遍历</span>
public class FileUtil { /* * 遍历目录下的所有文件和目录 */ 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(); //返回字符串数组,直接子的名称,不包含子目录下的内容 for (String string : fileNames) { System.out.println(string); }*/ File[] files = dir.listFiles(); if(files!=null && files.length>0) { for (File file : files) { System.out.println(file); if(file.isDirectory()) //递归遍历 { listDirectory(file); } } } } }
RandomAccessFile类:提供了对文件内容的访问,既可以读文件,也可以写文件。它提供对文件的随机访问,可以访问文件的任意位置
1>文件模式
java文件,在硬盘上是byte byte byte...存储的,是数据的集合
2>打开文件
打开文件有两种模式 “rw” 读写操作 “r” 只读操作
RandomAccessFile raf = new RandomAccessFile (file , "wr"),RandomAccessFile的随机访问是依靠文件指针实现的,打开文 件的默认指针位置prointer=0,即在文件的开头。读写操作会伴随着指针位置的移动。
3>写方法
raf.write(int), ----->只写一个字节,同时指针只想下一个位置,准备再次进行写操作
4>读方法
raf.read()---->只写一个字节
5>文件读写完成后一定要关闭,不然会发生意想不到的错误
public class RandomAccessFileDemo { public static void main(String[] args)throws IOException { File file = new File("demo"); if(!file.exists()) { file.createNewFile(); } RandomAccessFile raf = new RandomAccessFile(file, "rw"); System.out.println(raf.getFilePointer()); //获取文件指针的位置,0 raf.write('A');//只写入一个字节 System.out.println(raf.getFilePointer()); //1 int i = 0x7fffffff;//最大的整数 //用write方法,每次只能写一个字节,写一个int需要写4次 raf.write(i>>24); raf.write(i>>16); raf.write(i>>8); raf.write(i); //也可以直接写一个int,时机底层也是进行四次写操作 raf.writeInt(i); System.out.println(raf.getFilePointer()); String s="中国"; byte[] byte1 = s.getBytes("gbk"); raf.write(byte1); System.out.println(raf.length()); //文件的长度 13 //读文件必须把文件指针移到文件的开始,也可以移到指定的位置进行读取 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)+" "); } raf.close(); } }
字节流:
1>
InputStream 抽象了应用程序读取数据的方式,读到程序中为输入
OutputStream 抽象了应用程序写出数据的方式
2>
EOF =End 读到-1就读到了文件的结尾
3>输入流基本方法
int b = in.read(); 读取一个字节填充到int低八位
in.read(byte[] buf) ; 批量读取字节到字节数组中
in.read(byte[] buf , int start ,int size)
4>输出流基本方法
out.write(int b) // 写出int b 的低八位到流
out.write(byte[] b) ; 写出字节数组中的全部字节
out.write(byte[] b , int start ,int size) //从下表start开始,写出size个字节
5>具体实现类
FileInputStream --->具体实现了在文件中读取数据
/* * 读取指定文件内容,以十六进制输出到控制台 * 每读取10个字节换行, * 单字节读取,不适合大文件,效率很低 */ public class IOUtil { public static void printHex(String filename)throws IOException { FileInputStream fis = new FileInputStream(filename); int b; int i=1; while((b=fis.read())!=-1) //每次只读取一个字节 { if(b<=0xf) System.out.print("0"); //如果只有第四位,则在前面补零 System.out.print(Integer.toHexString(b)+" "); if(i++%10 == 0) { System.out.println(); } } fis.close(); } /* * 批量读取,大区大文件时效率很高 * 常用的文件读取方式 */ public static void printHexByByteArray(String filename)throws IOException { FileInputStream fis = new FileInputStream(filename); byte[] buffer = new byte[10*1024]; /* * 从fis中批量读取字节,放入到buf中,从第0个位置开始放,最多放buffer.length个字节 * 返回的是读取字节的个数 * 为了防止一次读不完一个文件,所以用到while循环,读到文件结尾为止 */ int n; while((n=fis.read(buffer, 0, buffer.length))!=-1) { int k=1; for (int i=0;i<n;i++) { if(buffer[i]<=0xf) System.out.print("0"); System.out.print(Integer.toHexString(buffer[i]&0xff)+" "); if(k++%10 == 0) System.out.println(); } } System.out.println(); fis.close(); } /* * 文件的copy */ 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[10*1024]; int n; while((n=in.read(buf, 0, buf.length))!=-1) { out.write(buf, 0, n); } }
public class FileOutputStreamDemo1 { public static void main(String[] args)throws IOException { //如果文件不存在,则创建该文件,如果该文件存在,则删除后再重新创建 FileOutputStream fos = new FileOutputStream("demo.dat",true); /* * 如果文件不存在,则创建该文件,如果文件存在,则以追加的方式向文件中写数据 * FileOutputStream fos = new FileOutputStream("demo.dat","true"); */ fos.write('A'); //写一个字节 String s = "中国"; byte[] b = s.getBytes(); fos.write(b); //写一个字节数组 fos.close(); } 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[10*1024]; int n; while((n=in.read(buf, 0, buf.length))!=-1) { out.write(buf, 0, n); } } }
DataInputStrean 和 DataOutputStrean 采用装饰模式,底层包装一个字节的读取操作
out.writeInt(10); out.writeInt(-10); out.writeLong(10l); out.writeDouble(1.11); out.writeUTF("中国"); out.writeChars("中国人");DataInputStrean中有与之对应的read操作
带缓冲的字节流
BufferedInputStream 和BufferedOutputStream,为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式,提高了IO的性能
public static void copyFileBuffer(File srcFile,File destFile)throws IOException { if(!srcFile.exists()) throw new IllegalArgumentException("原文件"+srcFile+"不存在"); if(!srcFile.isFile()) throw new IllegalArgumentException(srcFile+"不是文件"); BufferedInputStream in = new BufferedInputStream(new FileInputStream(srcFile)); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(destFile)); int n; while((n=in.read())!=-1) { out.write(n); out.flush();//必须写 } in.close(); out.close(); }
还可以自己写一个copyFileByByte(),经过比较,在进行较大的文件的copy工作时,自己创建byte[] 数组批量读取时,速度最快,带缓冲区的方式次之,当然可以想到,单个字节拷贝方式最慢。
字符流
1>认识文本和文本文件
java文本(char) 是16位无符号整数,是字符的Unicode编码(双字节编码)
文件是byte byte byte 。。 的序列集合文本文件是文本按照一定的编码方式序列化为byte的存储方式
2>字符流(Reader Writer)
字符流的底层仍然是基本的字节序列
字符流的基本实现 ---->操作文本文本文件
InputStreamReader -->完成byte流 解析为 char流 ,按照编码解析
OutputStreamWrite -->完成char流到byte流的解析,同样按照编码解析
public class FIRandFOW { public static void main(String[] args)throws IOException { FileInputStream in = new FileInputStream("C:\\unintall.log"); /* * 可以指定编码方式,自动识别换行 */ InputStreamReader reader = new InputStreamReader(in,"GBk"); FileOutputStream out = new FileOutputStream("C:\\unintall1.log"); OutputStreamWriter writer = new OutputStreamWriter(out,"GBk"); int a; /* 单个字符读取 while((a = reader.read())!=-1) { System.out.print((char)a); }*/ //批量读取 char[] buffer = new char[8*1024]; while((a=reader.read(buffer,0,buffer.length))!=-1) { writer.write(buffer, 0, a); writer.flush();//要加上刷新,才能及时将字符数组中的内容输出到文件 String s = new String(buffer,0,a); System.out.println(s); } } }
同 InputStreamReader 和 OutputStreamWriter读取字符和字符数组方式一样,只是创建对象的方式不同
DataInputStrean
FileReader read = new FileReader(file);
FileWriter write = new FileWriter(file); 构造函数的参数是File对象
注:这种字符流操作存在一些缺陷,我们看到在构造方法中没办法指定编码方式,所以,读取文件的编码必须和文件的编码相同,不然会出现乱码
字符流的过滤器
BufferedReader 和 BufferedWriter PrintWriter
优点是能以行为单位进行文件的读取
public class BufferReaderWriter { public static void main(String[] args) throws IOException { BufferedReader reader = new BufferedReader( new InputStreamReader(new FileInputStream("C:\\unintall.log"),"GBK")); //BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:\\unintall1.log"))); PrintWriter pwriter = new PrintWriter("C:\\unintall1.log"); String line; /* while((line = reader.readLine()) != null) { writer.write(line);//不识别换行 writer.newLine();//手动换行 writer.flush(); System.out.println(line); }*/ /* * 由于BufferedWriter创建对象比较复杂,并且不识别换行,所以用PrintWriter替代 */ while((line = reader.readLine()) != null) { pwriter.println(line); //用该方法进行换行 pwriter.flush(); System.out.println(line); } } }