黑马程序员_java IO流及文件操作详解
2014-08-25 11:25
495 查看
-------android培训、java培训、期待与您交流!
----------
java IO流操作
一、IO初步之File类
1、File类的介绍
File类在整个IO包中与文件本身有关的操作类,所有的与文件本身有关指的是创建、删除文件等操作。在java.io包中的File类本身是一个跨平台的文件操作类,所以在操作中要更多的考虑到各个操作系统的区别。
File 即指文件也指文件夹。
File类构造方法和字段摘要
static String pathSeparator :路径分隔符,window下是";"。
static char pathSeparatorChar :路径分隔符,window下是";"。
static String separator :路径分隔符,window下是"\"。
static char separatorChar: 路径分隔符,window下是"\"。
File(File parent, String child):根据 parent抽象路径名和 child路径名字符串创建一个新
File实例。
File(String pathname) :通过将给定路径名字符串转换为抽象路径名来创建一个新 File实例。
File(String parent, String child):根据 parent路径名字符串和 child路径名字符串创建一个新
File实例。
File(URI uri) :通过将给定的 file: /URI转换为一个抽象路径名来创建一个新的 File实例。
File的相关方法
String getName():返回文件名或路径名(若是路径,返回最后一级子路径名);
String getPath():返回对象对应的路径名;
File getAbsoluteFile():返回绝对路径;
String getAbsolutePath():返回对象对应的绝对路径;
String getParent():返回文件目录的上一级目录名;
boolean renameTo(File newName):重命名此File对象对应的文件或目录,若重命名成功返回true;
boolean exists():判断对象对应的文件或目录是否存在;
boolean canWrite():判断对象对应文件或目录是否可写;
boolean canRead():判断对象对应文件或目录是否可读;
boolean isFile():判断对象是文件,不是目录;
boolean isDirectory() :判断对象的文件是否是一个目录;
boolean isAbsolute():判断对象对应文件或目录是否为绝对路径名;
boolean createNewFile():当且仅当不存在,该方法创建一个该File对象所指定的新文件,创建成功返回true。
boolean delete():删除File对象所对应的文件或路径;
boolean mkdir() :创建File对象所对应的目录,调用该方法的File对象必须对应路径,而不是文件;
String[] list():列出File对象的所有子文件名和路径名;
File[] listFiles():列出File对象的所有子文件和路径;
static File[] listRoots():列出系统所有的根路径;
2、递归(Recursion)
现在要求输出一个给定目录中的全部文件的路径。
本程序肯定只能依靠递归的操作完成,因为在一个给定的路径下有可能还是文件夹,那么如果是文件夹的话则肯定要继续列出,重复判断。
递归:程序调用自身的编程技巧
递归就是在方法里调用自身;
在使用递归时,必须有一个明确的递归结束条件,称为递归出口。
3、文件过滤器 java.io.FilenameFilter
File 类里有方法: String[] list(FilenameFilter filter) 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
FilenameFilter(文件过滤器)该接口里包含accept(File dir,String name)方法,该方法依次对指定File的所有子目录,子文件夹进行迭代。
dir - 被找到的文件所在的目录。
name - 文件的名称。
当且仅当该名称应该包含在文件列表中时返回 true;否则返回 false
eg:按照文件目录结构层次输出file文件夹下所有.txt的文件。
二、IO流
1、IO流的概念及作用
流是一组有顺序的,有起点和终点的字节集合,是一串连续不断的数据的集合,就像水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流,数据写入程序可以使一段一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。流是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
在程序中所有的数据都是以流的方法进行传输和保存的。
Java 的IO是实现输入和输出的基础。
Java把所有传统的流类型(类或抽象类)都放在java.io包中,用以实现输入输出功能。
输入和输出是一个相对的概念,我们一般站在程序的角度来分析和处理问题的。
程序需要数据 -->读进来 --> 输入
程序保存数据 -->写出去 --> 输出
流的分类
从不同角度分类:
按流动方向的不同可以分为输入流和输出流;
按处理数据的单位不同分为字节流和字符流;
按功能的不同可分为节点流和处理流;
节点流:直接操作目标设备,例如:磁盘或一块内存区域。
处理流:通过操作节点流,从而间接完成输入或输出功能的流。处理流是的存在是建立在一个已经存在的输入流或输出流的基础之上的。
字节流和字符流
二者仅仅是操作单位不一样。
InputStream和Reader是所有输入流的基类,他们都是抽象类,本身不能创建实例,但是他们是所有输入流的模板。
一般来说处理字符或字符串时使用字符流,处理字节或二进制对象时应使用字节流;
备注:字符流必须关闭资源,因为它中间有缓冲区!而字节流不需要!但是一般都会(最后)关闭资源!
所有流都继承于以下四种抽象流类型的某一种(抽象流), 主要分为两类:
a、字节流
字节流主要是操作byte(字节)的类型数据:
字节输出流:OutputStream
字节输入流:InputStream
b、字符流
Java中的字符是Unicode编码,是双字节的,1个字符等于
2个字节;
使用字节来处理字符文本就不太方便了,此时可以考虑使用字符流;
字符流主要是操作char的类型数据:
字符输出流:Writer
字符输入流:Reader
字节流和字符流的区别
字节流和字符流在使用上的代码结构都是非常类似的,但是其内部本身也是有区别的,因为在进行字符流操作的时候会使用到缓冲区(内存中),而字节流操作的时候是不会使用到缓冲区的。
在输出的时候,OutputStream类即使最后没有关闭内容也可以输出。但是如果是Writer的话,则如果不关闭,最后一条内容是无法输出的,因为所有的内容都是保存在了缓冲区之中,每当调用了close()方法就意味着清空缓冲区了。那么可以证明字符流确实使用了缓冲区:
字节流:程序→文件(设备)
字符流:程序→缓冲区(内存中)→文件(设备)
2、操作流的步骤(重点)
流的操作规律:
1,明确源和目的。
数据源:就是需要读取,可以使用两个体系:InputStream、Reader;
数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;
2,操作的数据是否是纯文本数据?
如果是:数据源:Reader
数据汇:Writer
如果不是:数据源:InputStream
数据汇:OutputStream
3,虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?
明确操作的数据设备。
数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。
4,需要在基本操作上附加其他功能吗?比如缓冲。
但无论想要完成的操作是要使用字节流或字符流完成,亦或使用何种的输入输出流,以及它们的源和目的是什么,但是其基本的操作原理是一样的所以在此以文件流为准进行说明,File类本身是与文件操作有关:
1)、使用File类找到一个文件对象,得到IO操作的源或目标;
2)、通过字节流或字符流的子类创建对象,(得到IO操作的通道);
3)、进行读或写的操作(IO操作);
4)、关闭输入/输出(关掉资源);
由于流的操作属于资源操作,所以在操作的最后一定要关闭以释放资源。
计算机访问外部设备,要比直接访问内存慢得多,若我们每一次write方法调用都是直接写到外部设备(比如磁盘上的一个文件),CPU就要花费更多的时间去等待外部设备;我们可以开辟一个内存缓冲区,程序每一次的write方法都是写到这个内存缓冲区中,只有这个缓冲区装满了之后,系统才将这个缓冲区的内容一次集中写到外部设备。
输出:就将文件file.txt中的数据打印到了控制台!
3、常见的IO流
1)、字节字符转换流
OutputStreamWriter:把字节输出流对象转成字符输出流对象;
InputStreamReader:把字节输入流对象转成字符输入流对象;
FileWriter和FileReader分别是OutputStreamWriter和InputStreamReader的直接子类,而不是Writer和Reader的直接子类,区别于FileInputStream和InputStream,当不指定编码集时使用当前系统默认编码。
eg:
//构建一个字节输出流对象
OutputStream out = new FileOutputStream("");
//把字节输出流转成字符输出流
Writer w = new OutputStreamWriter(out);
//然后的操作和使用字符输出流的操作一样
---------------------------------------------
//构建一个字节输入流对象
InputStream is = new FileInputStream("");
//把字节输入流转成字符输入流
Reader r = new InputStreamReader(is);
//然后的操作和使用字符输入流的操作一样
2)、内存操作流
操作内存流的时候(从读取出来,注意一定要把真正的数据用toByteArray或者toCharArray将数据读出来)
之前的文件操作流是以文件的输入输出为主的,当输出的位置变成了内存,那么就称为内存操作流。此时要使用内存流完成内存的输入和输出操作。
如果程序运行过程中要产生一些临时文件,可采用虚拟文件方式实现;
直接操作磁盘的文件很耗性能,使用内存流可以提升性能;jdk里提供了内存流可实现类似于内存虚拟文件的功能。
ByteArrayInputStream:将内容写到内存中 CharArrayReader
ByteArrayOutputStream:将内存中的数据写出 CharArrayWriter
ByteArrayInputStream:构造方法:
public ByteArrayInputStream(byte[] buf):全部内容
public ByteArrayInputStream(byte[] buf,int offset,int length):指定范围的内容
ByteArrayOutputStream:
public ByteArrayOutputStream()
3)、打印流
(只有两个,PrintWriter和PrintStream)
思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便?
肯定是不方便的,因为OutputStream中只能操作字节数据,所以其他的数据类型很难操作,那么在Java的IO包中为了解决这种问题增加了两种类:PrintStream、PrintWriter。
打印流有非常好的打印功能,可以打印任何的数据类型。如,整数,小数,字符串等。
观察PrintStream类的构造:
public PrintStream(File file) throws FileNotFoundException
public PrintStream(OutputStream out)
虽然PrintStream是OutputStream的子类,但是在实例化的时候依然需要一个OutputStream的对象。
PrintWriter和PrintStream都属于输出流,分别针对字符和字节。
PrintWriter和PrintStream重载的print()和println()用于多种数据类型的输出。
print()里的参数不能为空;println()可以
PrintWriter和PrintStream输出操作不抛出异常
PrintStream调用println方法有自动flush功能;
4)、格式化输出
Java5后,PrintStream类多了printf()方法用于格式化输出操作。但是格式化输出的时候必须指定输出数据的类型:
(构造方法)
PrintStream format(String fo, Object... args)使用指定格式字符串和参数将格式化字符串写入此输出流中。
备注:当然你也可以全部使用“%s”来表示所有的数据类型!
格式:
需要格式 %占位符
5)、标准流
标准输入流: System.in 默认表示的是键盘录入
标准输出流: System.out 默认表示的是屏幕输出
6)、Scanner(简单文本扫描器)
Scanner(File source) 构造一个新的 Scanner,它生成的值是从指定文件扫描的。
备注:实现了Iterable接口
7)、缓冲流
缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率,同时增加了一些新的方法。
四种缓冲流
BufferedReader(Reader in)
BufferedReader(Reader in,int sz)//sz表示自定义缓冲区大小
BufferedWriter(Writer out)
BufferedWriter(Writer out,int sz)
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int sz)
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int sz)
BufferedReader提供readLine方法用于读取一行字符串。
BufferedWriter提供了newLine方法用于写入一个行分隔符。等价于//.writer("\r\n");
对于输出的缓冲流,写出的数据会先在内存中缓冲,使用flush方法将会使内存中的数据立刻写出。
8)、合并流(SequenceInputStream)
需要两个源文件,还有输出的目标文件
SequenceInputStream:
将两个文件的内容合并成一个文件
该类提供的方法:
SequenceInputStream(InputStream s1, InputStream s2):根据两个字节输入流对象来创建合并流对象。
备注:谁放在前面,谁就先打印出来
----------
java IO流操作
一、IO初步之File类
1、File类的介绍
File类在整个IO包中与文件本身有关的操作类,所有的与文件本身有关指的是创建、删除文件等操作。在java.io包中的File类本身是一个跨平台的文件操作类,所以在操作中要更多的考虑到各个操作系统的区别。
File 即指文件也指文件夹。
File类构造方法和字段摘要
static String pathSeparator :路径分隔符,window下是";"。
static char pathSeparatorChar :路径分隔符,window下是";"。
static String separator :路径分隔符,window下是"\"。
static char separatorChar: 路径分隔符,window下是"\"。
File(File parent, String child):根据 parent抽象路径名和 child路径名字符串创建一个新
File实例。
File(String pathname) :通过将给定路径名字符串转换为抽象路径名来创建一个新 File实例。
File(String parent, String child):根据 parent路径名字符串和 child路径名字符串创建一个新
File实例。
File(URI uri) :通过将给定的 file: /URI转换为一个抽象路径名来创建一个新的 File实例。
File的相关方法
String getName():返回文件名或路径名(若是路径,返回最后一级子路径名);
String getPath():返回对象对应的路径名;
File getAbsoluteFile():返回绝对路径;
String getAbsolutePath():返回对象对应的绝对路径;
String getParent():返回文件目录的上一级目录名;
boolean renameTo(File newName):重命名此File对象对应的文件或目录,若重命名成功返回true;
boolean exists():判断对象对应的文件或目录是否存在;
boolean canWrite():判断对象对应文件或目录是否可写;
boolean canRead():判断对象对应文件或目录是否可读;
boolean isFile():判断对象是文件,不是目录;
boolean isDirectory() :判断对象的文件是否是一个目录;
boolean isAbsolute():判断对象对应文件或目录是否为绝对路径名;
boolean createNewFile():当且仅当不存在,该方法创建一个该File对象所指定的新文件,创建成功返回true。
boolean delete():删除File对象所对应的文件或路径;
boolean mkdir() :创建File对象所对应的目录,调用该方法的File对象必须对应路径,而不是文件;
String[] list():列出File对象的所有子文件名和路径名;
File[] listFiles():列出File对象的所有子文件和路径;
static File[] listRoots():列出系统所有的根路径;
eg: package com.demo.file; import java.io.File; import java.io.IOException; public class FileDemo1 { public static void main(String[] args) throws IOException { File f = new File("E:/file.txt"); System.out.println(f.createNewFile()); System.out.println(f.getName()); System.out.println(f.getParent()); System.out.println(f.length()); } } 输出: false file.txt E:\ 1804
2、递归(Recursion)
现在要求输出一个给定目录中的全部文件的路径。
本程序肯定只能依靠递归的操作完成,因为在一个给定的路径下有可能还是文件夹,那么如果是文件夹的话则肯定要继续列出,重复判断。
递归:程序调用自身的编程技巧
递归就是在方法里调用自身;
在使用递归时,必须有一个明确的递归结束条件,称为递归出口。
//练习:列出文件夹下所有文件(包含子文件夹内) package com.demo.file; //利用递归遍历输出 import java.io.File; public class FileDemo2 { public static void main(String[] args) { File f = new File("D:/file"); listFileMeth(f); } public static void listFileMeth(File f) { System.out.println(f);//先输出一下,因为不能确定接受来的文件是否是文件夹! if (f.isDirectory()) { File[] files = f.listFiles(); for (File file : files) { listFileMeth(file); } } } }
//练习:删除一个目录(注意:要删除目录必须删除目录下的文件和子目录) package com.demo.file; import java.io.File; public class FileDemo3 { public static void main(String[] args) { File f = new File("D:/file"); deleteFiles(f); System.out.println("删除成功!"); } public static void deleteFiles(File f){//程序简陋,就没有判断空引用! if(f.isFile()){ f.delete(); }else if(f.isDirectory()){ File []files = f.listFiles(); for (File file : files) { deleteFiles(file);//调用自身,递归! file.delete();//删除子文件夹(内部没有文件的时候可以删除),如果这里写上f.delete();那么V5这个文件夹也没有了 } } } }
3、文件过滤器 java.io.FilenameFilter
File 类里有方法: String[] list(FilenameFilter filter) 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。
FilenameFilter(文件过滤器)该接口里包含accept(File dir,String name)方法,该方法依次对指定File的所有子目录,子文件夹进行迭代。
dir - 被找到的文件所在的目录。
name - 文件的名称。
当且仅当该名称应该包含在文件列表中时返回 true;否则返回 false
eg:按照文件目录结构层次输出file文件夹下所有.txt的文件。
package com.demo.file; import java.io.File; import java.io.FilenameFilter; public class FileListFilter { public static void main(String[] args)throws Exception { File parent=new File("d:/file/"); /*1、遍历file下所有txt文件。 File[] fs=parent.listFiles(new FilenameFilter(){ @Override public boolean accept(File dir, String name) { if(name.endsWith(".txt")){ return true; } return false; } }); for(File s:fs){ System.out.println(s.getName()); } */ //2、具有目录结构层次的遍历file文件夹下的所有txt文件 listFile(parent,0); } public static void listFile(File file,int level){ int depth=level;//用于记录递归遍历的深度; if(file.isFile()){ if(file.getName().endsWith(".txt")){ printSpace(depth);//每次输出文件名前先打印空白缩进; System.out.println(file.getName()); return; } return; } printSpace(depth); System.out.println(file.getName()); depth++; File[] fs=file.listFiles(); for(File f:fs){ listFile(f,depth); } } public static void printSpace(int depth){ for(int i=0;i<depth;i++) System.out.print(" "); } }
二、IO流
1、IO流的概念及作用
流是一组有顺序的,有起点和终点的字节集合,是一串连续不断的数据的集合,就像水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流,数据写入程序可以使一段一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。流是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
在程序中所有的数据都是以流的方法进行传输和保存的。
Java 的IO是实现输入和输出的基础。
Java把所有传统的流类型(类或抽象类)都放在java.io包中,用以实现输入输出功能。
输入和输出是一个相对的概念,我们一般站在程序的角度来分析和处理问题的。
程序需要数据 -->读进来 --> 输入
程序保存数据 -->写出去 --> 输出
流的分类
从不同角度分类:
按流动方向的不同可以分为输入流和输出流;
按处理数据的单位不同分为字节流和字符流;
按功能的不同可分为节点流和处理流;
节点流:直接操作目标设备,例如:磁盘或一块内存区域。
处理流:通过操作节点流,从而间接完成输入或输出功能的流。处理流是的存在是建立在一个已经存在的输入流或输出流的基础之上的。
字节流和字符流
二者仅仅是操作单位不一样。
InputStream和Reader是所有输入流的基类,他们都是抽象类,本身不能创建实例,但是他们是所有输入流的模板。
一般来说处理字符或字符串时使用字符流,处理字节或二进制对象时应使用字节流;
备注:字符流必须关闭资源,因为它中间有缓冲区!而字节流不需要!但是一般都会(最后)关闭资源!
所有流都继承于以下四种抽象流类型的某一种(抽象流), 主要分为两类:
a、字节流
字节流主要是操作byte(字节)的类型数据:
字节输出流:OutputStream
字节输入流:InputStream
b、字符流
Java中的字符是Unicode编码,是双字节的,1个字符等于
2个字节;
使用字节来处理字符文本就不太方便了,此时可以考虑使用字符流;
字符流主要是操作char的类型数据:
字符输出流:Writer
字符输入流:Reader
字节流和字符流的区别
字节流和字符流在使用上的代码结构都是非常类似的,但是其内部本身也是有区别的,因为在进行字符流操作的时候会使用到缓冲区(内存中),而字节流操作的时候是不会使用到缓冲区的。
在输出的时候,OutputStream类即使最后没有关闭内容也可以输出。但是如果是Writer的话,则如果不关闭,最后一条内容是无法输出的,因为所有的内容都是保存在了缓冲区之中,每当调用了close()方法就意味着清空缓冲区了。那么可以证明字符流确实使用了缓冲区:
字节流:程序→文件(设备)
字符流:程序→缓冲区(内存中)→文件(设备)
2、操作流的步骤(重点)
流的操作规律:
1,明确源和目的。
数据源:就是需要读取,可以使用两个体系:InputStream、Reader;
数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;
2,操作的数据是否是纯文本数据?
如果是:数据源:Reader
数据汇:Writer
如果不是:数据源:InputStream
数据汇:OutputStream
3,虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?
明确操作的数据设备。
数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。
4,需要在基本操作上附加其他功能吗?比如缓冲。
但无论想要完成的操作是要使用字节流或字符流完成,亦或使用何种的输入输出流,以及它们的源和目的是什么,但是其基本的操作原理是一样的所以在此以文件流为准进行说明,File类本身是与文件操作有关:
1)、使用File类找到一个文件对象,得到IO操作的源或目标;
2)、通过字节流或字符流的子类创建对象,(得到IO操作的通道);
3)、进行读或写的操作(IO操作);
4)、关闭输入/输出(关掉资源);
由于流的操作属于资源操作,所以在操作的最后一定要关闭以释放资源。
计算机访问外部设备,要比直接访问内存慢得多,若我们每一次write方法调用都是直接写到外部设备(比如磁盘上的一个文件),CPU就要花费更多的时间去等待外部设备;我们可以开辟一个内存缓冲区,程序每一次的write方法都是写到这个内存缓冲区中,只有这个缓冲区装满了之后,系统才将这个缓冲区的内容一次集中写到外部设备。
eg1: package com.demo.io; //构建输入流,读进来,输出到控制台! import java.io.FileInputStream; import java.io.InputStream; public class IODemo1 { public static void main(String[] args) throws Exception { //第一步:创建源! String filename = "file.txt"; //第二步:创建管道! InputStream ips = new FileInputStream(filename); //第三步:操作! byte []buff = new byte[1024]; int len;//定义缓冲区 while((len = ips.read(buff)) != -1){ System.out.println(new String(buff,0,buff.length));//输出到控制台!此时的输出流就是打印流! } //第四步:关闭资源(字符流必须关闭资源,因为它中间有缓冲区!对于字节流可以不用关闭,但是还是建议写上,习惯!) ips.close(); } }
输出:就将文件file.txt中的数据打印到了控制台!
/* 如果现在字符流即使不关闭也可以完成输出的话,则必须强制性清空缓冲区: 方法:public void flush() throws IOException */ eg2: package com.demo.io; //字符流读出来,这时候就不会出现乱码的情况,在进行文字操作的时候最好使用字符流! import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class IODemo2 { public static void main(String[] args) { File src = new File("file.txt"); readFile(src); } public static void readFile(File src){ Reader r = null; try { r = new FileReader(src); } catch (FileNotFoundException e) { e.printStackTrace(); } char []c = new char[1024]; int len; try { while((len = r.read(c)) != -1){ System.out.println(new String(c,0,c.length));//打印到控制台 } } catch (IOException e) { e.printStackTrace(); } try { r.close(); } catch (IOException e) { e.printStackTrace(); } } } <span style="color:black;"> </span>
/*文件拷贝 需求:源和目标! 那么我们需要源文件和目标文件! 构建管道的时候就需要两个:输出流和输入流管道! */ eg3: package com.demo.io; //java7开始的自动关闭资源 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class IODemo3 { public static void main(String[] args) throws IOException { File src = new File("E:/test.doc"); File tar = new File("E:/test1.doc"); copy(src, tar); System.out.println("Well done!"); } public static void copy(File src, File tar) throws IOException { try (InputStream is = new FileInputStream(src); OutputStream os = new FileOutputStream(tar);) { byte[] b = new byte[1024]; int len; while ((len = is.read(b)) != -1) { os.write(b); } <pre class="java" name="code">
/* 复制图片! 文件的复制!对于本题而言,因为是图片,所以要想读出来,必须使用字节流! 字符流必须关闭资源,而字节流可以不关闭资源!但是还是建议全部的关闭,因为也不会出错,这是关闭资源的习惯! 另外:最常用的是字节流,因为字节流在内存中不需要缓冲区,图片,mp3等都是字节流!但是对于文字的话还是字符流比较好; 因为字符流可以避免在字节流操作文字时出现的乱码现象(正好读取到了自定义缓冲区的分割处); */ eg4: package com.demo.io; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; public class IODemo4 { public static void main(String[] args) throws Exception { File src = new File("D:/demo.jpg"); File tar = new File("D:/copyofdemo.jpg"); copy(src,tar); System.out.println("复制完成!"); } public static void copy(File src,File tar) throws Exception{ /* Reader r = new FileReader(src); Writer w = new FileWriter(tar);*/ /*if(!src.exists()){ throw new Exception("对不起,源文件不存在!"); }*/ InputStream in = new FileInputStream(src); OutputStream os = new FileOutputStream(tar); byte []c = new byte[1024]; int len; while((len = in.read(c)) != -1){ os.write(c); } /* w.close(); r.close();*/ } } } catch (IOException e) { e.printStackTrace(); } } }
3、常见的IO流
1)、字节字符转换流
OutputStreamWriter:把字节输出流对象转成字符输出流对象;
InputStreamReader:把字节输入流对象转成字符输入流对象;
FileWriter和FileReader分别是OutputStreamWriter和InputStreamReader的直接子类,而不是Writer和Reader的直接子类,区别于FileInputStream和InputStream,当不指定编码集时使用当前系统默认编码。
eg:
//构建一个字节输出流对象
OutputStream out = new FileOutputStream("");
//把字节输出流转成字符输出流
Writer w = new OutputStreamWriter(out);
//然后的操作和使用字符输出流的操作一样
---------------------------------------------
//构建一个字节输入流对象
InputStream is = new FileInputStream("");
//把字节输入流转成字符输入流
Reader r = new InputStreamReader(is);
//然后的操作和使用字符输入流的操作一样
2)、内存操作流
操作内存流的时候(从读取出来,注意一定要把真正的数据用toByteArray或者toCharArray将数据读出来)
之前的文件操作流是以文件的输入输出为主的,当输出的位置变成了内存,那么就称为内存操作流。此时要使用内存流完成内存的输入和输出操作。
如果程序运行过程中要产生一些临时文件,可采用虚拟文件方式实现;
直接操作磁盘的文件很耗性能,使用内存流可以提升性能;jdk里提供了内存流可实现类似于内存虚拟文件的功能。
ByteArrayInputStream:将内容写到内存中 CharArrayReader
ByteArrayOutputStream:将内存中的数据写出 CharArrayWriter
ByteArrayInputStream:构造方法:
public ByteArrayInputStream(byte[] buf):全部内容
public ByteArrayInputStream(byte[] buf,int offset,int length):指定范围的内容
ByteArrayOutputStream:
public ByteArrayOutputStream()
eg: //此处用的是内存字节流(写入加输出) package com.demo.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; public class ByteArrayDemo { public static void main(String[] args) throws IOException { String s = "java is a good language"; ByteArrayOutputStream bos = new ByteArrayOutputStream();//输出流 bos.write(s.getBytes()); // 已经把信息写到了内存中 byte[] bys = bos.toByteArray();//得到真正的数据 ByteArrayInputStream bis = new ByteArrayInputStream(bys);//输入流,需要源。 byte[] b = new byte[1024]; int len; while ((len = bis.read(b)) != -1) { String data = new String(b, 0, len); System.out.println(data); } } } package com.demo.io; import java.io.CharArrayReader; import java.io.CharArrayWriter; public class CharArrayDemo { public static void main(String[] args) throws Exception { // 用内存字符流先把数据保存到内存中,然后从内存中取出数据 String s = <a target=_blank href="http://www.google.com">www.google.com</a>; CharArrayWriter cw = new CharArrayWriter(); cw.write(s);//数据写到了内存中 char[] ch = cw.toCharArray(); CharArrayReader cr = new CharArrayReader(ch); char[] b = new char[1024]; int len; while ((len = cr.read(b)) != -1) { String data = new String(b, 0, len); System.out.println(data); } } }
3)、打印流
(只有两个,PrintWriter和PrintStream)
思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便?
肯定是不方便的,因为OutputStream中只能操作字节数据,所以其他的数据类型很难操作,那么在Java的IO包中为了解决这种问题增加了两种类:PrintStream、PrintWriter。
打印流有非常好的打印功能,可以打印任何的数据类型。如,整数,小数,字符串等。
观察PrintStream类的构造:
public PrintStream(File file) throws FileNotFoundException
public PrintStream(OutputStream out)
虽然PrintStream是OutputStream的子类,但是在实例化的时候依然需要一个OutputStream的对象。
PrintWriter和PrintStream都属于输出流,分别针对字符和字节。
PrintWriter和PrintStream重载的print()和println()用于多种数据类型的输出。
print()里的参数不能为空;println()可以
PrintWriter和PrintStream输出操作不抛出异常
PrintStream调用println方法有自动flush功能;
eg: package com.demo.io; import java.io.FileWriter; import java.io.PrintStream; import java.io.PrintWriter; public class PrintDemo { public static void main(String[] args) throws Exception { PrintStream ps = new PrintStream("out.txt"); // ps.write(112); ps.println(2222); ps.println(false); // ps.print();针对print而言,不可以出现这样的(无参) ps.println();//此时就可以 //备注:System.out.println();想当于ps = System.out; ps = System.out; ps.println("您好!");//控制台操作,注意上一句 // 字符打印流 PrintWriter pr = new PrintWriter("out2.txt"); // PrintWriter(OutputStream out, boolean autoFlush)通过现有的 OutputStream,创建新的 PrintWriter。(构造方法) pr = new PrintWriter(new FileWriter("out2.txt"), true);//自动刷新,否则的话需要关闭资源! // 与PrintStream不同,若PrintWriter使用了自动刷新方法,那么必须调用println,print,format这些方法的其中一个才可以实现操作 pr.println("hehe"); pr.println(false); pr = new PrintWriter(System.out, true);//打印在控制台上 pr.println(false); pr.println(<a target=_blank href="http://www.google.com">www.google.com</a>); pr.println(376430645); // pr.close();//因为使用了自动刷新。 } }
4)、格式化输出
Java5后,PrintStream类多了printf()方法用于格式化输出操作。但是格式化输出的时候必须指定输出数据的类型:
(构造方法)
PrintStream format(String fo, Object... args)使用指定格式字符串和参数将格式化字符串写入此输出流中。
备注:当然你也可以全部使用“%s”来表示所有的数据类型!
格式:
需要格式 %占位符
eg: package com.demo.io; import java.io.FileWriter; import java.io.PrintStream; import java.io.PrintWriter; public class PrintStreamDemo { public static void main(String[] args) throws Exception { PrintStream ps = new PrintStream("E:/name.txt"); ps.write("1234341".getBytes()); ps.println(false); ps.print(false); PrintWriter pw = new PrintWriter(new FileWriter("E:/name1.txt"),true); pw.println("我们的未来!");//write不可以 pw = new PrintWriter(System.out,true); pw.println("我们的未来!");//打印在控制台上 String name = "zhangsan"; int age = 13; char score = 'A'; String format = "姓名=%s,年龄=%d,成绩=%c"; System.out.printf(format,name,age,score); int i = System.in.read();//流的重定向 System.out.println((char)i); } }
5)、标准流
标准输入流: System.in 默认表示的是键盘录入
标准输出流: System.out 默认表示的是屏幕输出
eg: package com.demo.io; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintStream; public class SyetemDemo { public static void main(String[] args) throws IOException { /* 标准流: 标准输入流: System.in默认表示的是键盘录入 标准输出流: System.out默认表示的是屏幕输出 若现在我输出不想打印在屏幕上,怎么办? 若现在我不想通过键盘来录入数据,有怎么办? 流的重定向: static void setOut(PrintStream out)重新分配“标准”输出流。 static void setIn(InputStream in)重新分配“标准”输入流。 */ System.out.println("123456789");//最普通的打印 System.err.println("123652");//同样是一种输出流,打印出的是123652 /* static void setOut(PrintStream out)重新分配“标准”输出流。 */ // 输出流就被重新定义到了文件,而不是屏幕 System.setOut(new PrintStream("68Demo.txt"));//只有在定义过后才生效,所以上面的还是会输出到控制台 System.out.println("AAAA"); System.out.println("BBBB");//就输出了在文件里 int i = System.in.read();//接受从键盘输入的数据,写在最前面(没有任何重新分配)才有效 System.out.println("i所对应的是:" + (char) i);//把它转换为字符型 System.out.println(i); /* 重新分配,由标准键盘输入变为由文件输入 */ System.setIn(new FileInputStream("copy6.4"));//备注:打印的是文件copy6.4中的数据,而且打印在文件68Demo.txt中。 byte[] buff = new byte[1024]; int len = 0; while ((len = System.in.read(buff)) != -1) { System.out.println(new String(buff, 0, len));//此时不会打印在控制台上,因为上面已经重新定义了由打印到屏幕上转换为打印到文件里 } } }
6)、Scanner(简单文本扫描器)
Scanner(File source) 构造一个新的 Scanner,它生成的值是从指定文件扫描的。
备注:实现了Iterable接口
package com.demo.io; import java.io.File; import java.io.PrintStream; import java.util.Scanner; public class ScannerDemo { public static void main(String[] args) throws Exception { // 参照api Scanner sc = new Scanner(System.in);//从键盘输入 // int i = System.in.read(); /* 连着进行了三次,没有完成的话不停止运行 System.out.println(sc.next()); System.out.println(sc.next()); System.out.println(sc.next()); */ System.setOut(new PrintStream("Scanner.txt"));//流的重定向(打印到哪里) sc = new Scanner(new File("copy6.4"));//扫描位置 int line = 1; while (sc.hasNextLine()) {//是否有下一行 //一行一行的读取,这样的话格式好看 System.out.println(line + " " + sc.nextLine());//读取下一行 line++; } } }
/*猜数字游戏: 1. 系统随机生成一个数字[1,100]; 2. 从键盘录入一个数字,[1,100] 3. 判断输入的数字和随机数比较: 随机数 >输入数:你输入太小了 随机数 < 输入数:输入太大了 随机数 = 输入数: 恭喜哦 思考:先想怎么生成一个随机数;然后怎么在键盘中录入一个随机数,第三步就是比较了;但是注意的是:需要确保输入的数据为数字,而且有范围的限制! */ package com.demo.io; import java.util.Random; import java.util.Scanner; public class IODemo { public static void main(String[] args) { guess(); } public static void guess(){ int i = new Random().nextInt(100)+1; System.out.println(i); System.out.println("请输入随机数来匹配,您有五次机会!"); Scanner sc = new Scanner(System.in);//键盘录入 for (int j = 0; j < 5; j++) { String s = sc.nextLine(); if(!s.matches("\\d+")){ System.out.println("请确认您输入的是数字"); break; } Integer in = new Integer(s); if(in > 100 | in < 0){ System.out.println("请确认您输入的数字在0到100之间!"); } switch (in.compareTo(i)) { case 1: System.out.println("您输入的数字过大!"); System.out.println("请输入:"); break; case -1: System.out.println("您输入的数字过小!"); System.out.println("请输入:"); break; default: System.out.println("恭喜您,您输入的数字正好匹配!"); return; } } } }
7)、缓冲流
缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率,同时增加了一些新的方法。
四种缓冲流
BufferedReader(Reader in)
BufferedReader(Reader in,int sz)//sz表示自定义缓冲区大小
BufferedWriter(Writer out)
BufferedWriter(Writer out,int sz)
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int sz)
BufferedOutputStream(OutputStream out)
BufferedOutputStream(OutputStream out,int sz)
BufferedReader提供readLine方法用于读取一行字符串。
BufferedWriter提供了newLine方法用于写入一个行分隔符。等价于//.writer("\r\n");
对于输出的缓冲流,写出的数据会先在内存中缓冲,使用flush方法将会使内存中的数据立刻写出。
eg: package com.demo.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; //用缓冲流,性能相对高些 public class BufferedInputStreamDemo { public static void main(String[] args) throws IOException { /* BufferedInputStream bis = new BufferedInputStream(new FileInputStream("68.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("buffer.txt")); int len = 0; while((len = bis.read()) != -1){ bos.write(len); } bos.close(); bis.close(); */ try ( BufferedReader br = new BufferedReader(new FileReader("68.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter( "bufferWriter.txt"))) {//java7新特性,自动关闭资源 String Line = null; while ((Line = br.readLine()) != null) { bw.write(Line); bw.newLine();//此时必须加上换行操作,注意这是个新用法(方法) } } catch (Exception e) { e.printStackTrace(); } } }
8)、合并流(SequenceInputStream)
需要两个源文件,还有输出的目标文件
SequenceInputStream:
将两个文件的内容合并成一个文件
该类提供的方法:
SequenceInputStream(InputStream s1, InputStream s2):根据两个字节输入流对象来创建合并流对象。
备注:谁放在前面,谁就先打印出来
eg: package com.demo.io; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.SequenceInputStream; //和并两个文件的合并流 public class SequenceInputStreamDemo { public static void main(String[] args) throws IOException { SequenceInputStream si = new SequenceInputStream( new FileInputStream("world.java"), new FileInputStream("hello.java")); OutputStream os = new FileOutputStream("sequence.txt"); int len; byte []b = new byte[1024]; while((len = si.read(b)) != -1){ os.write(b, 0, len); } } }
相关文章推荐
- java io流对文件的操作详解
- Java对各种文件的操作详解
- Java对各种文件的操作详解
- Java文件操作详解
- Delphi操作流文件详解
- C#中的文件操作详解
- Java文件操作详解
- VC操作文件之:CFile操作详解
- JAVA文件操作详解
- Java对各种文件的操作详解
- 灰灰虫的家---ADO.NET+DataList+GridView内容详解+C#基础+C#操作XML文件
- Java对各种文件的操作详解
- Java对各种文件的操作详解
- Java文件操作详解
- Java对各种文件的操作详解
- Windows XP 控制台命令详解 - 目录和文件操作命令
- Java文件操作详解
- Java文件操作详解
- 对Java编程中的文件操作详解
- C语言文件操作函数(ANSI)详解(一)