javaIO类--File类
--------------------
File类
是对文件系统中文件以及目录(文件夹)进行封装的对象,可以通过面向对象的思想来操作文件和目录(文件夹)。File类保存文件或目录的各种元素的信息,包括文件名,文件长度,最后修改日期,是否可读,获取当前文件的路径名,判断指定文件是否存在,获得当前文件的列表,创建、删除文件目录等方法。
/**
* 构造方法:File f = new File("file.txt");//file.txt 相对路径
* File f1 = new File("c:"+File.separator+"abc"+File.separator+"lp", "b.txt");//c:\abc\lp\b.txt 绝对路径
File f2 = new File(File d, child);
常用方法:
新建文件:
boolean createNewFile() 如果文件存在,则返回false,不会被覆盖,这和输出流不一样,IO输出流每次都会覆盖
public static File createTempFile(String prefix, String suffix) throws IOException
在默认的情况下创建一个临时空文件,给定前缀(abc)和后缀(.tmp)
public static File createTempFile(String prefix, String suffix, File directory) throws IOException
指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称
directory如果为null,使用默认的路径, 在windows上为C盘存放Tmp的目录下面,UNIX下面通常是"/tmp"或"/var/temp
创建目录:
boolean mkdirs() 可以递归的创建不存在的目录,创建多级目录
boolean mkdir() 创建目录,不能递归,如果存在不能创建,
删除文件: boolean delete() 删除File对象所对应的文件和路径
public void deleteOnExit() 在虚拟机终止时,请求删除此抽象路径名表示的文件或目录
判断:
boolean exists() 测试此抽象路径名表示的文件或目录是否存在。
boolean isDirectory() 测试此抽象路径名表示的文件是否是一个目录。
boolean isFile() 测试此抽象路径名表示的文件是否是一个标准文件。
获取:
String getName()
String getParent()
String getPath()
String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。
File getAbsoluteFile() 返回此抽象路径名的绝对路径名所对应的File对象
long lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
long getFreeSpace() 获取指定分区(例如D盘)可用的空间,或者剩余的空间
long getUsableSpace() 获取分区(例如D盘的可用于虚拟机的空间
long getTotalSpace()获取分区(例如D盘)总容量
重命名:boolean renameTo(File dest) :把某个路径下的文件重命名,从一个盘重命名后剪切到另一个盘
列出指定目录下面的文件:
String[] list() 返回文件或者目录的名字,是字符串类型
File[] listFiles() 返回文件或者目录对象,通过getName获取文件或者路径名称
文件过滤:
String[] list(FilenameFilter filter)
FilenameFilter-->>boolean accept(File dir, String name)
可以使用此方法列出指定目录下面的带有某些后缀的文件
*
*/
下面是看jdk6的测试代码:
public class FileDemo { public static void main(String[] args) throws IOException { //createFileMethod(); listRoots(); } //创建文件 public static void createFileMethod(){ File file = new File("file.txt"); try { boolean b = file.createNewFile(); System.out.print(b); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //创建临时文件 public static void createTempFileMethod(){ File dir = new File("D:\\"); try { File b = File.createTempFile("test", ".tmp",dir);//使用指定目录的方法 System.out.print(b.getAbsolutePath()); File b1 = File.createTempFile("tmp2", null);//使用不指定目录的构造方法 System.out.print(b1.getAbsolutePath()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //创建目录 public static void createDirMethod(){ File dir = new File("d:"+File.separator+"dfr"+File.separator+"ddd"); File dir1 = new File("d:"+File.separator+"dff"+File.separator+"ddd"); boolean b = dir.mkdirs();//可以递归的创建不存在的目录 boolean b1 = dir1.mkdir();//创建目录,不能递归,只能创建一级目录 System.out.println(b); System.out.println(b1); } //删除文件 public static void deleteFileMethod(){ File file = new File("file.txt"); try { boolean b = file.createNewFile(); System.out.print(b); file.deleteOnExit(); file.delete(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //判断文件对象或者目录是否是文件或者目录时候,必须判断该文件是否存在 public static void IsDirOrFileMethod() throws IOException{ File file = new File("a.txt"); File file1 = new File("d:"+File.separator+"hhh"); file.createNewFile(); file1.mkdir(); System.out.println("是否存在"+file.exists()); System.out.println("是否是文件"+file.isFile()); System.out.println("是否是目录"+file.isDirectory()); System.out.println("是否是隐藏"+file.isHidden()); System.out.println("目录是否为绝对目录名"+file1.isAbsolute()); System.out.println("file对象对应的文件目录是否可write: "+file1.canWrite()); System.out.println("file对象对应的文件目录是否可read: "+file1.canRead()); System.out.println("file对象对应的文件目录是否可Execute: "+file1.canExecute()); } //获取的方法 public static void getMehtod(){ File file = new File("E:\\file2.txt"); File dir = new File("abc"); System.out.println("获取抽象路径名转化为路径名字字符串:"+file.getPath());//E:\file2.txt System.out.println("获取此File对象对应的绝对路径名:"+file.getAbsolutePath());//E:\file2.txt System.out.println("获取此File对象的所对应目录(最后一级子目录(绝对路径))的父目录名:"+file.getParent());//E:\ System.out.println("获取此File对象最后修改时间:"+file.lastModified());//1405853667765,修改日期的毫秒数 } //相当于重命名剪切 public static void renameFile() throws IOException{ File f1 = new File("D:\\file.txt"); File f2 = new File("E:\\file2.txt"); System.out.println("f1重命名为f2的名字"+f1.renameTo(f2)); //System.out.println("f2重命名为f1的名字"+f2.renameTo(f1)); } //列出根目录的全部内容 public static void listRoots(){ File[] files = File.listRoots(); for(File file:files){ System.out.println("列出根目录:"+file); } } //列出指定的目录的全部内容,包括隐藏文件,文件夹的名字和文件的名字 public static void listDemo(){ File f = new File("d:\\"); System.out.println("获取D盘的可用空间"+f.getFreeSpace()); System.out.println("获取D盘的可用于虚拟机的空间"+f.getUsableSpace()); System.out.println("获取D盘的总容量"+f.getTotalSpace()); String[] files = f.list(); for(String file:files){ System.out.println("列出根目录:"+file); } } //列出指定的目录的全部内容,包括隐藏文件,文件夹的名字和文件的名字 public static void listFileterDemo(){ File f = new File("d:\\"); String[] files = f.list(); for(String file:files){ System.out.println("列出根目录:"+file); } } //列出指定的目录的全部内容,包括隐藏文件,文件夹的名字和文件的名字,使用 File[] listFiles() //返回值为一个File对象 public static void listFileDemo(){ File f = new File("d:\\"); File[] files = f.listFiles(); for(File file:files){ System.out.println("列出根目录:"+file.getName()); } } /** * 列出指定目录下,后缀为.java的文件,使用方法String[] list(FilenameFilter filter) */ public static void ListFileFileter(){ File f = new File("E:"+File.separator+"workspace"+File.separator+"IOTest"); String[] files = f.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { // TODO Auto-generated method stub //System.out.println("dir:"+dir+"name....."+name);//说明dir表示指定目录,name表示指定目录的名称 return name.endsWith(".java");//通过匿名内部类的返回值来控制指定目录下面的文件和文件夹的显示 } }); System.out.println(files.length); //遍历指定目录下面的文件和目录 for(String file:files){ System.out.println(file); } } }
java基础知识回顾之javaIO类--File类应用:递归深度遍历文件
代码如下:
package com.lp.ecjtu.File.FileDeepList; import java.io.File; public class FileDeepList { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub File dir = new File("E:"+File.separator+"demodir"); showDirDeep(dir,0); } /** * 深度遍历目录下面的内容,递归,包含子目录的内容 * @param dir */ public static void showDir(File dir){ File[] files = dir.listFiles(); for(int i=0;i<files.length;i++){ if(dir.exists()){ if(files[i].isDirectory()){//如果是文件夹,继续列出指定子文件夹的内容 showDir(files[i]);//使用递归 }else{ System.out.println(files[i].getName());//是文件 } } } } /** * 深度遍历目录下面的内容,递归,包含子目录的内容,并且使得遍历的目录有层次,加个层次计数器,第几层就加几 * @param dir 目录或者文件 * @param level 深度遍历层次计数器 */ public static void showDirDeep(File dir,int level){ if(!dir.exists()){ System.out.println("遍历的目录为空!"); } System.out.println(getSpace(level)+dir.getName()); level++; File[] files = dir.listFiles(); for(int i=0;i<files.length;i++){ if(files[i].isDirectory()){//如果是文件夹,继续列出指定子文件夹的内容 showDirDeep(files[i],level);//使用递归 }else{ System.out.println(getSpace(level)+files[i].getName());//是文件 } } } /** * 格式化层次 * @param level * @return */ private static String getSpace(int level) { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); for(int i=0;i<level;i++){//几层就拼几个字符 sb = sb.append("|--"); } return sb.toString(); } }
-----------------------------------------
FilenameFilter和FileFilter都是用来过滤文件,例如过滤,以.jpg或者.java结尾的文件,通过看他们的源码:通过使用File类中String[] list(FilenameFilter filter)或者public File[] listFiles(FileFilter filter)方法,把FilenameFilter或者FileFilter接口对象作为参数传入,通过实现接口里面的 boolean accept(File dir, String name) 或者boolean accept(File pathname)方法来过滤出满足条件的文件:区别:FilenameFilter的性能比FileFilter的好.
/**
File类:
* 使用 String[] list(FilenameFilter filter)遍历指定目录下面,指定的后缀的文件。
底层怎么实现过滤的?
String[] list(FilenameFilter filter)
原理:先把目录下面的文件调用list()方法全部存放到一个String[]数组里面,然后遍历数组,
把符合filter.accept(this, names[i])条件的放到一个ArrayList里面,然后把
List转化为String[]数组
底层源码解析:
public String[] list(FilenameFilter filter) {
String names[] = list();//把所有目录文件列出来
if ((names == null) || (filter == null)) {//如果没有目录或者文件,返回null
return names;
}
ArrayList v = new ArrayList();
for (int i = 0 ; i < names.length ; i++) {//找到文件,遍历
if (filter.accept(this, names[i])) {
v.add(names[i]);/把满足条件的放到List集合中
}
}
return (String[])(v.toArray(new String[v.size()]));
}
* FilenameFilter 接口
* 接口方法:
* boolean accept(File dir,String name) 可以使用此方法列出指定目录下面的带有某些后缀的文件。
参数:
dir - 被找到的文件所在的目录。
name - 文件的名称。
返回:
当且仅当该名称应该包含在文件列表中时返回 true;否则返回 false。
*
*/
代码:
1.需求找出某个路径下面以.java结尾的文件。
实现:FilenameFilter 接口:
package com.lp.ecjtu.File.filter; import java.io.File; import java.io.FilenameFilter; public class FileterByJava implements FilenameFilter { private String SufixName;//传入过滤的名称 public FileterByJava(String SufixName){ this.SufixName = SufixName; } @Override public boolean accept(File dir, String name) { //System.out.println("dir"+dir+"_____"+"name"+name);//返回dir:E:\workspace\IOTest_____name:buf.txt } }
package com.lp.ecjtu.File.filter; import java.io.File; import java.io.FilenameFilter; public class FileListFilter { public static void main(String[] args){ ListFileFileterByjava(); } /** * * 使用实现FilenameFilter接口的方法, * 过滤String[] list(FilenameFilter filter) * 文件名过滤 */ public static void ListFileFileterByjava(){ File f = new File("E:"+File.separator+"workspace"+File.separator+"IOTest"); String[] fileNames = f.list(new FileterByJava(".java"));//使用具体对象,把过滤后的以.java文件的文件放到数组当中 System.out.println(fileNames.length);//含有.java文件数组的长度 for(String name:fileNames){//遍历找到的.java文件 System.out.println(name); } } /** * 列出指定目录下,后缀为.java的文件,使用方法String[] list(FilenameFilter filter)使用匿名内部类的方法 */ public static void ListFileNameFileter(){ File f = new File("E:"+File.separator+"workspace"+File.separator+"IOTest"); String[] files = f.list(new FilenameFilter() {//使用匿名内部类的方法 @Override public boolean accept(File dir, String name) { // TODO Auto-generated method stub //System.out.println("dir:"+dir+"name....."+name);//测试说明dir表示指定目录,name表示指定目录的名称 return name.endsWith(".java");//通过匿名内部类的返回值来控制指定目录下面的文件和文件夹的显示,只显示.java文件 } }); System.out.println(files.length); //遍历指定目录下面的文件和目录 for(String file:files){ System.out.println(file); } } }
/ * FileFilter接口
* 接口方法:
* boolean accept(File dir,String name) 可以使用此方法列出指定目录下面的带有某些后缀的文件。
参数:
dir - 被找到的文件所在的目录。
name - 文件的名称。
返回:
当且仅当该名称应该包含在文件列表中时返回 true;否则返回 false。
*/
代码:
需求:现在要求输入一个文件的目录,之后将里面所有的备份文件删除,备份文件都是以“.bak”或".BAK"结尾,也就是说过滤文件类型为.bak或者.BAK文件后进行删除.
第一种方法,使用FileFilter内部类的方法,进行操作:
代码:
package com.lp.ecjtu.File.filter; import java.io.File; import java.io.FileFilter; public class FileFilterDemo { public static void main(String[] args){ File dir = new File("E:\\复件 demodir"); ListFileFileter(dir); } /** * 现在要求输入一个文件的目录,之后将里面所有的备份文件删除,备份文件都是以“.bak”或".BAK"结尾,过滤文件类型为.bak文件 */ public static void ListFileFileter(File dir){ if(dir.exists()){ //匿名内部类,把FileFilter接口对象作为参数 File[] files = dir.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { if(pathname.isDirectory()){ return true; } String name = pathname.getName();//获取文件的名称E:\复件 demodir\Learn\sgim_piccell.v1.bin.bak System.out.println("****************"+pathname); return name.endsWith(".bak")|| name.endsWith(".BAK");//过滤文件类型为.bak或者.BAK文件,而不包含.BAK或者.bak的文件 } }); //深度遍历文件,递归 for(int i=0;i<files.length;i++){ if(files[i].isFile()){//如果遍历到的是文件,直接删除 files[i].delete(); }else{//还是目录,继续遍历,直到是文件,再删除 ListFileFileter(files[i]); } } }else{ throw new RuntimeException("操作的文件或者目录不存在!"); } } }
第二中方法实现接口,使用真实类的对象:
package com.lp.ecjtu.File.filter; import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; /** * * 需求:输入一个文件目录,之后将里面所有备份的文件删除,备份文件都是以".bak" 和".BAK"结尾 * */ public class FileterByFile implements FileFilter { @Override public boolean accept(File pathname) { if(pathname.isDirectory()){ return true; } String name = pathname.getName(); // TODO Auto-generated method stub System.out.println("****************"+pathname); return name.endsWith(".bak")|| name.endsWith(".BAK"); } }
package com.lp.ecjtu.File.filter; import java.io.File; import java.io.FileFilter; public class FileFilterDemo { public static void main(String[] args){ File dir = new File("E:\\复件 demodir"); ListFileFileterBak(dir); } /**
* 删除满足条件的文件
* @param dir
*/ public static void ListFileFileterBak(File dir){ if(dir.exists()){ File[] files = dir.listFiles(new FileterByFile());//使用过滤 for(File file:files){ if(file.isDirectory()){ ListFileFileterBak(file); }else{ file.delete(); } } }else{ throw new RuntimeException("操作的文件或者目录不存在!"); } } }
java基础知识回顾之javaIO类--File类应用:删除带内容的目录
/**
* 深度删除一个带内容的目录
* 原理:必须从里往外删除,需要深度遍历
* @author Administrator
*
*/
public class FileDeleteList { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub File dir = new File("E:\\复件 demodir"); removedir(dir); } /** * 递归的从里向外删除文件盒目录 * @param dir */ private static void removedir(File dir) { if(dir.exists()){ File[] files = dir.listFiles(); for(File file:files){ /* if(file.isDirectory()){//文件是目录继续遍历里面的目录,直到找到文件目录里面的文件 removedir(file); }else{ System.out.println(file.getAbsolutePath()+file.delete());//删除目录里面的文件 }*/ if(file.isFile()){//是否是文件,是文件的话,直接删除 System.out.println(file.getAbsolutePath()+file.delete());//删除目录里面的文件 }else{ removedir(file);//不是文件,是目录,递归的遍历,直到是文件 } } System.out.println(dir.getAbsolutePath()+dir.delete());//删除目录从里向外删除 }else{ throw new RuntimeException("删除的目录文件不存在"); } } }
java基础知识回顾之javaIO类--File类应用:获取指定目录下面的指定扩展名的文件,将文件的绝对路径写入到目的文件当中
/**
* File文件综合应用
* 需求:获取指定目录下面,指定扩展名的文件,将文件的绝对路径写到文本文件当中。
*
* 思路:1.需要深度遍历。--递归
* 2.遍历的过程中过滤指定扩展名的文件--过滤器FileNameFilter,将文件存入容器中
* 3.将容器中的内容遍历,写入到指定文件中
*
*/
代码:
FilenameFilter 过滤器:
package com.lp.ecjtu.File.filter; import java.io.File; import java.io.FilenameFilter; public class FileterByJava implements FilenameFilter { private String SufixName;//传入过滤的名称 public FileterByJava(String SufixName){ this.SufixName = SufixName; } @Override public boolean accept(File dir, String name) { System.out.println("dir:"+dir+"_____"+"name:"+name); return name.endsWith(SufixName); } }
主程序:程序都有注释,请看程序
import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * File文件综合应用 * 需求:获取指定目录下面,指定扩展名的文件,将文件的绝对路径写到文本文件当中。 * * 思路:1.需要深度遍历。--递归 * 2.遍历的过程中过滤指定扩展名的文件--过滤器FileNameFilter,将文件存入容器中 * 3.将容器中的内容遍历,写入到指定文件中 * */ public class FileNameFileterWriteFile { /** * @param args */ public static void main(String[] args) { File dir = new File("E:\\demodir"); FilenameFilter fileter = new FileterByJava(".bak");//过滤.bak文件 List<File>fileList = new ArrayList<File>(); getFileList(dir,fileter,fileList); File desFile = new File(dir, "FileList.txt"); write2File(fileList, desFile); } /** * * @param dir 需要遍历的目录 * @param filter 过滤满足条件的文件 * @param fileList 存放符合条件的容器 */ public static void getFileList(File dir,FilenameFilter filter,List<File>fileList){ if(dir.exists()){ File[] files = dir.listFiles();//找到目录下面的所有文件 for(File file:files){ //递归 if(file.isDirectory()){ getFileList(file,filter,fileList); }else{ //对遍历的文件进行过滤,符合条件的放入List集合中 if(filter.accept(dir, file.getName())){ fileList.add(file); } } } } } /** * 将容器中的文件遍历,写入到目的文件中 * @param list 存放满足条件的文件的集合 * @param desFile 要写入的目的文件 */ public static void write2File(List<File>fileList,File desFile){ BufferedWriter bw = null; try { //使用字符流写入到目的文件中 bw = new BufferedWriter(new FileWriter(desFile)); //遍历List集合 for(File file:fileList){ bw.write(file.getAbsolutePath());//写入目的文件绝对路径 bw.newLine(); bw.flush(); } } catch (IOException e) { e.printStackTrace(); }finally{ try { if(bw != null){ bw.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
输出:在指定的目录下面创建目的文件:FileList.txt,里面存放:
E:\demodir\FileDir\Professional_32_2052.dat.bak
E:\demodir\FileDir\sgim_piccell.v1.bin.bak
E:\demodir\FileDir\sgim_picidx.v1.bin.bak
-----------------------------------------
类 RandomAccessFile
RandomAccessFile(File file, String mode)
RandomAccessFile(String name, String mode)
public void seek(long pos) throws IOException 设置指针的初始位置
public long getFilePointer()throws IOException 返回指针的位置,就是从开头的偏移量,以字节为单位。
mode 参数指定用以打开文件的访问模式:
值 |
含意 |
---|---|
"r" | 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException 。 |
"rw" | 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 |
"rws" | 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 |
"rwd" | 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。 |
代码:
在ranacc.txt写入,张三,97,王强,99
//使用RandomAccessFile对象写入一些人员信息,比如姓名和年龄。 public static void writeFile() throws IOException{ /* * 如果文件不存在,则创建,如果文件存在,不创建 * */ RandomAccessFile raf = new RandomAccessFile("ranacc.txt","rw"); raf.write("张三".getBytes()); raf.writeInt(97); raf.write("小强".getBytes()); raf.writeInt(99); // raf.close(); }
在RandomAccessFile对象的字节数组中存放如下图所示:
汉字为两个字节,数字为一个字节:
然后需求要求读小强的信息,把小强,99输出。
这就用到RandomAccessFile对象中的seek方法。
/** * 读取小强的信息,而不是张三的信息 * @throws IOException */ public static void readFile() throws IOException { RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "r"); //通过seek设置指针的位置。 raf.seek(1*8);//随机的读取。只要指定指针的位置即可。 byte[] buf = new byte[4]; raf.read(buf); String name = new String(buf);// int age = raf.readInt();//从当前指针开始读4个字节 System.out.println("name="+name); System.out.println("age="+age); System.out.println("pos:"+raf.getFilePointer());//获取指针的位置 raf.close(); }
输出:
name=小强
age=99
pos:16
-----------------------------------------
管道流(线程通信流):管道流的主要作用是可以进行两个线程间的通讯,分为管道输出流(PipedOutputStream)、管道输入流(PipedInputStream),如果想要进行管道输出,则必须要把输出流连在输入流之上。如图所示:
1.管道输入流应该连接到管道输出流 ,输入流和输出流可以直接连接
2.使用多线程操作,结合线程进行操作。通常由某个线程从管道输入流中(PipedInputStream)对象读取。
并由其他线程将其写入到相应的端到输出流中。不能使用单线程对输入流对象向和输出流对象进行操作,因为会造成 死锁问题。
3.管道流连接:(1)使用构造方法进行连接PipedOutputStream(PipedInputStream snk) 创建连接到指定管道输入流的管道输出流。
(2)public void connect(PipedInputStream snk)throws IOException,使用connect方法进行连接
下面看代码:
package com.lp.ecjtu.io.piped; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class PipedDemo { public static void main(String[] args) { PipedOutputStream out = new PipedOutputStream(); PipedInputStream in = new PipedInputStream(); try { out.connect(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }//输出管道流连接输入管道流 new Thread(new OutputThread(out)).start(); new Thread(new InputThread(in)).start(); } } class InputThread implements Runnable{ private PipedInputStream in; public InputThread(PipedInputStream in){ this.in = in; } @Override public void run() { // TODO Auto-generated method stub try { byte[] buff = new byte[1024]; int len = in.read(buff); String s = new String(buff,0,len); System.out.println(s); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class OutputThread implements Runnable{ private PipedOutputStream out; public OutputThread(PipedOutputStream out){ this.out = out; } @Override public void run() { String str = "hello Piped!"; try { out.write(str.getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { if(out != null){ out.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
java基础知识回顾之javaIO类--内存操作流ByteArrayInputStream和ByteArrayOutputSteam(操作字节数组)
直接看代码:
package cn.itcast.io.p6.bytestream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class ByteArrayStreamDemo { /** * @param args * @throws IOException * 特点 * 1.内存操作流 * 2.不操作底层资源,不调用操作系统的底层资源,操作内存中的数据,内存流不需要关闭 * 3.关闭流后还可以使用 * 本例:内存操作流完成的一个大小写字母转换的程序: */ public static void main(String[] args) { String str = "HELLO WORLD!"; ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());//将内容输入到内存中 ByteArrayOutputStream bos = new ByteArrayOutputStream();//将内存中的数据输出 int ch = 0; bis.skip(2);//跳过两个字节 System.out.println(bis.available());//返回此输入流读取的(或跳过)剩余的字节数 while((ch=bis.read())!=-1){ bos.write(Character.toLowerCase(ch));//将大小字符转化成小写 } System.out.println(bos.toString()); } }
输出:由于跳过两个字节,HELLO WORLD!总共12个字节,则剩余10个字节。
10
llo world!
-----------------------------------------
FileWriter类的构造方法定义如下:
1.public FileWriter(File file)throws IOException
字符流的操作比字节流操作好在一点,就是可以直接输出字符串了,不用再像之前那样进行转换操作了。
package com.lp.ecjtu; import java.io.FileWriter; import java.io.IOException; public class FileWriterDemo { /** * 字符流,创建一个FileWriter对象,该对象一被初始化,就必须明确操作的文件,将 * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub //而且该文件被创建到指定目录下,如果该目录下面已经有同名的文件,将被覆盖 FileWriter fw = new FileWriter("Demo.txt"); //调用write方法,将字符串写入到流当中去,也就是缓冲区中 fw.write("abcefg"); //刷新流对象中的缓冲中的数据 //将数据刷到指定的文件当中去 fw.flush(); //fw.close();//如果用close,则流关闭,后面的写入流将不会被执行 fw.write("3423"); fw.flush(); } }
输出结果:
在Demo.txt文件中写入了:abcefg3423
2.public FileWriter(File file,boolean append)throws IOException 用FileWriter的另一种构造方法,传递一个true参数,代表不覆盖已有的文件。并在已有文件进行续写
package com.lp.ecjtu; import java.io.FileWriter; import java.io.IOException; /** * 对已有文件的续写 * @author Administrator * */ public class FileWriterDemoApend { /** * 创建一个FileWriter对象,该对象一被初始化,就必须明确操作的文件 * @param args * @throws IOException * @throws IOException */ public static void main(String[] args){ FileWriter fw = null; try{ //用FileWriter的另一种构造方法,传递一个true参数,代表不覆盖已有的文件。并在已有文件进行续写 fw = new FileWriter("Demo.txt",true); //调用write方法,将字符串写入到流当中去,也就是缓冲区中 fw.write("234334\r\n谢谢"); }catch (IOException e) { e.printStackTrace(); }finally{ try { if(fw != null){ fw.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
输出结果:在文件中续写字符串:
结果变为
abcefg3423234334
FileReader的构造方法定义如下:
public FileReader(File file)throws FileNotFoundException
FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader。
例子:一个字符一个字符读取文件:
package com.lp.ecjtu; import java.io.FileReader; import java.io.IOException; public class FileReaderDemo { /** * 怎样去捕获IO异常,标准的捕获异常方式 * 下面的1,2,3都会抛出异常,可能发生的异常有下面三个: * 1.java.io.FileNotFoundException //关联的文件不存在 * 2.java.lang.NullPointerException //FileReader可能没有new * 3.IOException //操作IO流的时候抛出的异常 */ public static void main(String[] args) { //创建一个文件读取流对象,和指定的名称的文件相关联 //要保证该文件是已经存在的,如果不存在,会发生FileNotFoundException FileReader fr = null; try { fr = new FileReader("Demo.txt"); //一次读取一个字符,而且会自动往下读 /* int char1 = fr.read(); System.out.println("char1="+(char)char1);//char1=a int char2 = fr.read(); System.out.println("char2="+(char)char2);//char2=b int char3 = fr.read(); System.out.println("char3="+(char)char3);//char3=c int char4 = fr.read(); System.out.println("char4="+(char)char4);//char4=e int char5 = fr.read(); System.out.println("char5="+(char)char5); int char6 = fr.read(); System.out.println("char6="+(char)char6); int char7 = fr.read(); System.out.println("char7="+char7);*/ //如果达到流的末尾,则返回-1,-1为数据的分割符 int ch = 0; while((ch=fr.read())!= -1){ System.out.print((char)ch); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(fr != null){ try { fr.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
输出结果:
abcefg3423234334
谢谢
以字符数组的形式读取:
使用:
public int read(char[] cbuf) throws IOException
package com.lp.ecjtu; import java.io.FileReader; import java.io.IOException; public class FileReaderDemo2 { /** * @param args */ public static void main(String[] args) throws IOException{ //创建一个文件读取流对象,和指定的名称的文件相关联 //要保证该文件是已经存在的,如果不存在,会发生FileNotFoundException FileReader fr = new FileReader("Demo2.txt"); //定义一个字符数组,用于存储读到的字符 //char[] ch = new char[1024]; //返回读到的字符个数 //每次读3字符个放到字符数组缓冲区当中,一次性存储3个放到数组当中,然后在一次性读取出来 char[] ch = new char[3]; int num = fr.read(ch); System.out.println("num="+num+"----"+new String(ch)); int num1 = fr.read(ch); System.out.println("num1="+num1+"----"+new String(ch)); int num2 = fr.read(ch); System.out.println("num2="+num2+"----"+new String(ch)); int num3 = fr.read(ch); System.out.println("num3="+num3+"----"+new String(ch)); int nu = 0; while((nu=fr.read(ch)) !=-1){ System.out.println(new String(ch,0,nu)); } fr.close(); } }
输出:demo2中存储的字符为:abcdefg
num=3----abc
num1=3----def
num2=1----gef
num3=-1----gef
以字符数组的的形式循环读取java文件
package com.lp.ecjtu; import java.io.FileReader; import java.io.IOException; public class FileReaderJava { /** * @param args * 读取一个java文件,并且打印到控制台上 */ public static void main(String[] args) throws IOException{ //创建一个文件读取流对象,和指定的名称的文件相关联 //要保证该文件是已经存在的,如果不存在,会发生FileNotFoundException FileReader fr = new FileReader("FileReaderDemo.java"); //定义一个字符数组,用于存储读到的字符 char[] ch = new char[1024]; //返回读到的字符个数 int num= 0; while((num=fr.read(ch)) !=-1){ System.out.print(new String(ch,0,num)); } fr.close(); } }
文件的复制:将一个盘的文件复制到另一个盘:
package com.lp.ecjtu; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyTest { /**将C盘一个文本文件复制到D盘 * @param args * 原理:其实就是将C盘下的文件数据存储到D盘的文件当中 * 步骤: * 1.在D盘创建一个文件,用于存储C盘文件的数据 * 2.定义读取流和C盘文件相关联 * 3.通过不断的读写完成数据的存储 * 4.关闭资源 * @throws IOException */ public static void copy1() throws IOException{ //创建要写出到哪个文件,也就是目的地:为硬盘文件 FileWriter fw = new FileWriter("testjava.txt"); //与要拷贝的文件关联,也就是读取要拷贝的文件 源:为硬盘文件 FileReader fr = new FileReader("FileReaderDemo.java"); int ch=0; //从c盘 读一个,就往D盘复制一个 while((ch = fr.read())!= -1){ fw.write(ch); } fw.close(); fr.close(); } /** * 写入数组缓存中,一次读出,一次性写入 * @param args * @throws IOException */ public static void copy2(){ FileWriter fw = null; FileReader fr = null; try { fw = new FileWriter("test2.txt"); fr = new FileReader("FileReaderDemo.java"); char[] buf = new char[1024]; int len = 0;//表示buf数组的长度 while((len = fr.read(buf))!=-1){ fw.write(buf,0,len); System.out.println(buf); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { if(fw != null){ fw.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(fr != null){ fr.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) throws IOException { copy1(); copy2(); } }
总结:copy1的效率低于copy2,因为copy2一次性把数组复制到数组缓冲区,然后在写入流中。
-----------------------------------------
使用了装饰设计模式:此类的设计是为了提高流操作数据的效率。思想就是定义容器将数据进行临时存储,对于缓冲区对象,其实就是将这个容器进行了分装,并提供了更高效的操作方法。
BufferReader:
package com.lp.ecjtu; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class BufferReaderDemo { /** * @param args * @throws IOException * * 该缓冲去提供了一个的读取一行 readLine()方法,当返回null时读到末尾 */ public static void main(String[] args) throws IOException { //创建一个读取流对象和文件相关联 FileReader fr = new FileReader("FileReaderDemo.java"); //为了提高字符读取的效率,加入缓冲技术 //将需要被提高效率的流对象作为参数传入缓冲区的构造方法即可 BufferedReader bw = new BufferedReader(fr); String line = null; /*line = bw.readLine(); System.out.println("******"+line);//一次性读取一行 String line1 = bw.readLine(); System.out.println("******"+line1); String line2 = bw.readLine(); System.out.println("******"+line2);*/ while((line=bw.readLine()) != null){ System.out.println(line); } bw.close(); } }
BufferWriter:
package com.lp.ecjtu; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class BufferWriterDemo { /** * @param args * @throws IOException * * 该缓冲去提供了一个跨平台的换行符 newLine方法 */ public static void main(String[] args) throws IOException { //创建一个字符写入流对象 FileWriter fw = new FileWriter("buf.txt"); //为了提高字符写入的效率,加入缓冲技术 //将需要被提高效率的流对象作为参数传入缓冲区的构造方法即可 BufferedWriter bw = new BufferedWriter(fw); for(int i=0;i<5;i++){ bw.write("abcd"+i); bw.newLine(); bw.flush(); } } }
通过缓冲区将一个文本的内容复制到另一个文件当中:
package com.lp.ecjtu; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class CopyTextByBuffer { /** * @param args * readLine()方法返回回车符之前数据的内容,并不返回回车符,可以通过newLine()方法换行 */ public static void main(String[] args) { BufferedReader bufr = null; BufferedWriter bufw = null; try { bufr = new BufferedReader(new FileReader("FileReaderDemo.java")); bufw = new BufferedWriter(new FileWriter("bufferWriterCopy.txt")); String line = null; while((line=bufr.readLine())!=null){ bufw.write(line); bufw.newLine(); bufw.flush(); } } catch (FileNotFoundException e) { throw new RuntimeException("没有找到指定文件!请确认文件名称是否正确!"); }catch (IOException e) { throw new RuntimeException("读写失败!"); }finally{ try { if(bufr != null){ bufr.close(); } } catch (IOException e) { throw new RuntimeException("读取关闭失败!"); } try { if(bufw != null){ bufw.close(); } } catch (IOException e) { throw new RuntimeException("写入关闭失败!"); } } } }
原理;
1,使用流的read方法从源中读取一批数据存储到缓冲区的数组中。
2,通过计数器记录住存储的元素个数。
3,通过数组的角标来获取数组中的元素(从缓冲区中取数据).
4,指针会不断的自增,当增到数组长度,会归0.计数器会自减,当减到0时,就在从源拿一批数据进缓冲区。
package com.lp.ecjtu; import java.io.FileReader; import java.io.IOException; class MybufferReader { private FileReader r; public MybufferReader(FileReader r){ this.r = r; } //可以一次性读一行数据的方法 public String myreadLine() throws IOException{ StringBuilder sb = new StringBuilder(); int ch = 0; while((ch = r.read()) != -1){ if(ch == '\r'){ continue; } if(ch == '\n'){ return sb.toString(); }else{ sb.append((char)ch); } } if(sb.length() != 0){ return sb.toString(); } return null; } public void myClose() throws IOException{ r.close(); } } public class MybufferReaderDemo{ public static void main(String[] args) throws IOException{ FileReader fr = new FileReader("buf.txt"); MybufferReader mybuffer = new MybufferReader(fr); String line = null; while((line =mybuffer.myreadLine())!= null){ System.out.println(line); } mybuffer.myClose(); } }
-----------------------------------------
package com.lp.ecjtu; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * * @author Administrator * 1.用字节读取流对象和图片相关联(输入流) * 2.用字节写入流对象创建一个图片文件。用于存储获取到的图片数据(输出流) * 3.通过循环读写,完成数据的储存 * 4.关闭资源 * */ public class CopyPicStream { /** * @param args */ public static void main(String[] args) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("d:\\1.jpg");//读取图像数据之类的原始字节流 fos = new FileOutputStream("2.bmp");//用于写入诸如图像数据之类的原始字节流 byte[] b = new byte[1024]; int len = 0; while ((len=fis.read(b)) != -1){ fos.write(b); } }catch (FileNotFoundException e) { e.printStackTrace(); }catch (IOException e) { throw new RuntimeException("复制图片失败!"); }finally{ try { if(fis != null){ fis.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(fos != null){ fos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
InputStreamReader和OutputStreamWriter转化流
InputStreamReader:是字节流通向字符流的桥梁;
OutputStreamWriter 是字符流通向字节流的桥梁;
package com.lp.ecjtu; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; public class SystemReadInKeyTranfer { /** * 1.源:键盘 * 目的:控制台 * 2.源:键盘录入:把键盘录入的数据存储到一个文件中 * 目的:文件 * 3.源:文件:将文件中的数据打印在控制台上 * 目的:控制台 * 流操作的基本流程: * 通过两个明确来完成 * 1 明确源和目的 * 源:输入流,InputStream Reader * 目的:输出流 :outputStream Writer * 2.操作的是否为纯文本 * 是:字符流 * 不是:字节流 * 3.当体系明确后,在明确使用哪个具体的对象。 * 通过来设备来区分: * 源设备:内存,硬盘,键盘 * 目的:内存,硬盘,控制台 * 1.将一个文本文件中的数据存储到另一个文件。复制文件。 * 源:因为是源,所以使用读取流。InputStream Reader * 是文本文件:这是可以选择Reader * 明确设备:硬盘上的一个文件 * Reader体系中可以操作文件的FileReader * 是否提高效率,是,加入Reader体系中的BufferedReader * FileReader fr = new FileReader("a.txt"); * BufferedReader buffr = new BufferedReader(fr); * * 目的:outputStream Writer * 是否为纯文本,是!用字符流 Reader. * 设备:硬盘上的文件. * Writer体系中可以操作文件的FileWriter * 是否提高效率,是,加入Writer体系中的BufferedWriter * FileWriter fr = new FileWriter("a.txt"); * BufferedWriter buffr = new BufferedWriter(fr); * * 2.将一个图片文件中的数据存储到另一个文件。复制文件。 */ public static void main(String[] args){ BufferedReader bufferr = null; BufferedWriter bufferw = null; try { //将System.in->InputStream->Reader对象 //将Reader对象包装成BufferedReader对象 //键盘录入 /*bufferr = new BufferedReader(new InputStreamReader(System.in)); //把键盘录入的数据存储到out.txt文件当中 bufferw= new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt"))); */ //将文件中的数据与bufferedReader相关联,InputStreamReader字节向字符转化的桥梁。 bufferr = new BufferedReader(new InputStreamReader(new FileInputStream("FileReaderDemo.java"))); //将文件的数据打印到控制台,OutputStreamWriter字符向字节转化的桥梁 bufferw = new BufferedWriter(new OutputStreamWriter(System.out)); String line = null; //采用循环的方式逐个读取 while((line=bufferr.readLine())!=null){ //如果读取的字符串为“over”的时候,则程序退出 if(line.equals("over")){ System.exit(-1);//或者用break } //打印读取的内容 //System.out.println(line.toUpperCase()); //使用字符输出流进行输出 bufferw.write(line.toUpperCase()); bufferw.newLine();//跨平台换行,不用'\r\n' bufferw.flush(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { if(bufferr != null){ bufferr.close(); } if(bufferw != null){ bufferw.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
BufferedInputStream和BufferedOutputStream
MP3的复制过程:
package com.lp.ecjtu; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * * @author Administrator * 演示MP3的复制 * BufferedOutputStream * BufferedInputStream * */ public class CopyMp3Stream { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { long startTime = System.currentTimeMillis(); copy_1(); long endTime = System.currentTimeMillis(); System.out.println("共耗费"+(endTime-startTime)+"毫秒"); } public static void copy_1() throws IOException{ //创建一个内部缓冲数组,读硬盘中的数据到缓冲区中,字节流缓冲区 BufferedInputStream bufIos = new BufferedInputStream(new FileInputStream("D:\\1.mp3")); BufferedOutputStream buffos = new BufferedOutputStream(new FileOutputStream("2.mp3")); int by = 0; while((by=bufIos.read()) != -1){//读取缓冲区的数据到输入流中 buffos.write(by);//对输出流进行写操作 } buffos.close(); bufIos.close(); } }
ByteBuffer用法小结
在 NIO中,数据的读写操作始终是与缓冲区相关联的.读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲 区.缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型.ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且 信道的读写方法只接收ByteBuffer.因此ByteBuffer的用法是有必要牢固掌握的.
1.创建ByteBuffer
1.1 使用allocate()静态方法
ByteBuffer buffer=ByteBuffer.allocate(256);
以上方法将创建一个容量为256字节的ByteBuffer,如果发现创建的缓冲区容量太小,唯一的选择就是重新创建一个大小合适的缓冲区.
1.2 通过包装一个已有的数组来创建
如下,通过包装的方法创建的缓冲区保留了被包装数组内保存的数据.
ByteBuffer buffer=ByteBuffer.wrap(byteArray);
如果要将一个字符串存入ByteBuffer,可以如下操作:
String sendString="你好,服务器. ";
ByteBuffer sendBuffer=ByteBuffer.wrap(sendString.getBytes("UTF-16"));
2.回绕缓冲区
buffer.flip();
这个方法用来将缓冲区准备为数据传出状态,执行以上方法后,输出通道会从数据的开头而不是末尾开始.回绕保持缓冲区中的数据不变,只是准备写入而不是读取.
3.清除缓冲区
buffer.clear();
这个方法实际上也不会改变缓冲区的数据,而只是简单的重置了缓冲区的主要索引值.不必为了每次读写都创建新的缓冲区,那样做会降低性能.相反,要重用现在的缓冲区,在再次读取之前要清除缓冲区.
4.从套接字通道(信道)读取数据
int bytesReaded=socketChannel.read(buffer);
执行以上方法后,通道会从socket读取的数据填充此缓冲区,它返回成功读取并存储在缓冲区的字节数.在默认情况下,这至少会读取一个字节,或者返回-1指示数据结束.
5.向套接字通道(信道)写入数据
socketChannel.write(buffer);
此方法以一个ByteBuffer为参数,试图将该缓冲区中剩余的字节写入信道.
-----------------------
ByteBuffer俗称缓冲器, 是将数据移进移出通道的唯一方式,并且我们只能创建一个独立的基本类型缓冲器,或者使用“as”方法从 ByteBuffer 中获得。ByteBuffer 中存放的是字节,如果要将它们转换成字符串则需要使用 Charset , Charset 是字符编码,它提供了把字节流转换成字符串 ( 解码 ) 和将字符串转换成字节流 ( 编码) 的方法。
private byte[] getBytes (char[] chars) {//将字符转为字节(编码)
Charset cs = Charset.forName ("UTF-8");
CharBuffer cb = CharBuffer.allocate (chars.length);
cb.put (chars);
cb.flip ();
ByteBuffer bb = cs.encode (cb)
return bb.array();
}
private char[] getChars (byte[] bytes) {//将字节转为字符(解码)
Charset cs = Charset.forName ("UTF-8");
ByteBuffer bb = ByteBuffer.allocate (bytes.length);
bb.put (bytes);
bb.flip ();
CharBuffer cb = cs.decode (bb);
return cb.array();
}
通 道也就是FileChannel,可以由FileInputStream,FileOutputStream,RandomAccessFile三个类来 产生,例如:FileChannel fc = new FileInputStream().getChannel();与通道交互的一般方式就是使用缓冲器,可以把通道比如为煤矿(数据区),而把缓冲器比如 为运煤车,想要得到煤一般都通过运煤车来获取,而不是直接和煤矿取煤。用户想得到数据需要经过几个步骤:
一、用户与ByteBuffer的交互
向ByteBuffer中输入数据,有两种方式但都必须先为ByteBuffer指定容量
ByteBuffer buff = ByteBuffer.allocate(BSIZE);
a) buff = ByteBuffer.wrap("askjfasjkf".getBytes())注意:wrap方法是静态函数且只能接收byte类型的数据,任何其他类型的数据想通过这种方式传递,需要进行类型的转换。
b) buff.put();可以根据数据类型做相应调整,如buff.putChar(chars),buff.putDouble(double)等
二、FileChannel 与 ByteBuffer的交互:
缓冲器向通道输入数据
FileChannel fc = new FileInputStream().getChannel();
fc.write(buff);
fc.close();
三、 用户与ByteBuffer交互
通道向缓冲器送入数据
FileChannel fc = new FileOutputStream().getChannel();
fc.read( buff);
fc.flip();
四、呈现给用户(三种方式)
1)String encoding = System.getProperty("file.encoding");
System.out.println("Decoded using " + encoding + ": " + Charset.forName(encoding).decode(buff));
2)System.out.println(buff.asCharBuffer());//这种输出时,需要在输入时就进行编码getBytes("UTF-8")
3) System.out.println(buff.asCharBuffer());//通过CharBuffer向ByteBuffer输入 buff.asCharBuffer().put
-----------------------------------------
-----------------------------------------