**IO流java中的IO流按照数据类型分为两种:字节流(用得最多)和字符流(多用于处理文档)。
IO流按流向分为:输入流,输出流。**
字节流的抽象基类:InputStream,OutputStream
字符流的抽象基类:Reader,Writer
1.字符流Writer和Reader
1.1在硬盘上创建一个文件并且写入文字数据
static void createFileAndWrite(){
try {
//FileWriter是Writer的子类。如果文件不存在会在D盘下创建文件。
Writer writer=new FileWriter("D:/test.txt");
//写入字符串数据
writer.write("zhangsan");
//写入之后,数据是在内存中,必须调用flush()方法刷新,将数据从内存写入文件
writer.flush();
//关闭资源,此方法执行之前,会自动调用flush()方法刷新数据,将内存中的数据写入到文件后再关闭。
writer.close();
} catch (IOException e) {
System.err.println(e.toString());
}
}
在D盘创建文件,还可以写成:
Writer writer=new FileWriter("D:\\test2.txt");
因为“\”在java中表示转义字符,所以用”\”来表示文件层次。
Writer writer=new FileWriter("D:/test2.txt",true);
表示在test2.txt文件后面追加数据,而不会覆盖test2.txt以前就存在的数据。
1.2 FileReader读取硬盘文档上的数据。
1.2.1 read()方法(不常用)
FileReader 的read()方法返回的是所读到字符的ASCII码。如果读到了文件的末尾,则会返回-1.所以以-1作为循环条件。
代码:
static void readFile(){
try {
Reader reader=new FileReader("D:/test2.txt");
int count=0;
while((count=reader.read())!=-1){
//将ASCII码转化为字符
System.out.print((char)count);
}
reder.close();
} catch (IOException e) {
e.printStackTrace();
}
}
1.2.2 read(char[])方法
FileReader的read(char[])是将文件里面的数据读入到char[]缓冲区里面。返回的是每次读取到的个数。如果已经到文件
末尾,则返回-1.read(char[])方法逐位覆盖char缓冲区里面的数据。每执行一次此方法,都会覆盖掉char缓冲区里面原有的数据。
代码:
static void readFile2(){
try {
Reader reader=new FileReader("D:/test2.txt");
char[]buf=new char[1024];
int num=0;
while((num=reader.read(buf))!=-1){
System.out.print(new String(buf,0,num));
}
reder.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
1.3复制文件(将文件从一个磁盘复制到另一个磁盘)。
思路:
- 创建写对象和读对象。构造方法为文件路径。
- 创建字符数组作为缓冲区。
- 数据读到缓冲区以后,马上写入指定文件,完成文件复制。
- 关闭资源。
代码:
static void copyFile(){
FileReader fileReader=null;
FileWriter fileWriter=null;
try {
fileReader=new FileReader("D:/code.java");
fileWriter=new FileWriter("E:/code.java");
//定义缓冲区
char[]buf=new char[1024];
int len=0;
while((len=fileReader.read(buf))!=-1){
fileWriter.write(buf, 0, len);//写入到新文件中
System.out.print(new String(buf,0,len));//数据打印到控制台
}
} catch (IOException e) {
throw new RuntimeException("出错了");
}
//关闭资源
finally{
if(fileReader!=null)
try {
fileReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(fileWriter!=null)
try {
fileWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.字符流缓冲区
字符流缓冲区对应的类有BufferedWriter和BufferedReader。
缓冲区的出现是为了提高流的操作效率出现的。字符流缓冲区和使用数组作为缓冲区原理基本一致。先将数据读或写到缓冲区(内存)中。当缓冲区满了的时候,在硬盘上进行读写操作。避免了频繁读写硬盘,提高了效率。
因此在创建缓冲区之前,必须先要有流对象。
2.1BufferedWriter向硬盘写数据
代码:
static void bufferTest1() throws IOException{
//创建FileWriter对象
FileWriter fileWriter=new FileWriter("D:/test.txt");
//创建BufferedWriter对象,以FileWriter对象作为构造参数
BufferedWriter bufferedWriter=new BufferedWriter(fileWriter);
//写一个Hello BufferedWriter就换行
for(int i=0;i<6;i++){
bufferedWriter.write("Hello BufferedWriter"+i);
bufferedWriter.newLine();//换行
bufferedWriter.flush();//必须刷新,将数据从内存写到硬盘上
}
bufferedWriter.close();//关闭资源,关闭之前,会刷新一次。
}
2.1 BufferedReader读硬盘数据
BufferedWriter除了拥有FileReader的两个重载的read方法外,还可以读取一行文本。简化了程序,提高了效率。
readLine()方法读取的是每行的有效数据,并不包含每行结尾处的换行符。
代码:
static void bufferRead1()throws IOException{
//创建FileReader对象
FileReader fileReader=new FileReader("D:/test.txt");
//创建BufferedReader对象,以FileReader对象作为构造参数
BufferedReader bufferedReader=new BufferedReader(fileReader);
//BufferedReader可以读取一行文本,该方法返回String。如果读到末尾,返回null。
String dataString=null;
while((dataString=bufferedReader.readLine())!=null){
System.out.println(dataString);
}
bufferedReader.close();//读完关闭资源
}
2.3 Buffered实现文本文档拷贝
static void bufferCopy()throws IOException{
//创建Buffered读写对象
BufferedReader bufferedReader=new BufferedReader(new FileReader("D:/code.java"));
BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("E:/code2.java"));
String dataString=null;
while((dataString=bufferedReader.readLine())!=null){
bufferedWriter.write(dataString);
System.out.println(dataString);
bufferedWriter.newLine();//写完一行,就换行,因为readLine只读取有效数据,不包含换行符
bufferedWriter.flush();//写完一行,就刷新一次
}
//关闭资源。
bufferedReader.close();
bufferedWriter.close();
}
3. 装饰类
新建一个类,将需要装饰的类作为该类的构造方法参数。该类中的方法实现调用装饰类中的方法,但进行加强。
例如BufferedReader类中的readLine()方法就是基于FileReader的read()方法来实现的。
装饰类的构造方法参数里面的一定有被装饰类。
class MyBufferedReader extends Reader{
private FileReader fileReader;
public MyBufferedReader(FileReader fileReader){
this.fileReader=fileReader;
}
public void myReadLine(){
//调用FileReader的read()方法实现具体的readLine方法
}
//...还需要覆盖Reader中的抽象方法,此处省略
}
4. 其他
**因为BufferedReader和BufferedWriter对缓冲区进行了封装,不需要char数组,因此使用相比
FileReader和FileWriter方便一些。**
5. 字节流
字节流的抽象基类:InputStream,OutputStream
字节流的缓冲区是字节数组
5.1 字节流写文件
代码:
static void outputStreamTest1 ()throws IOException{
//会创建一个文件
FileOutputStream outputStream=new FileOutputStream("D:/test2.txt");
String string="锄禾日当午" +"\r\n"+"汗滴禾下土";
outputStream.write(string.getBytes());//必须是字节数组
outputStream.close();
}
5.2 字节流读文件
代码:
static void inputStreamTest1()throws IOException{
FileInputStream inputStream=new FileInputStream("D:/test2.txt");
byte[] bytes=new byte[1024];//创建字节缓冲区
int len=0;
//如果读到末尾,则返回-1
while((len=inputStream.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
inputStream.close();
}
第二种字节流读文件方式(不建议使用)
代码:
/**
* 因为缓冲区的大小和文件一样,所以不用循环读数据,直接从缓冲区读数据即可。
* @throws IOException
*/
static void inputStreamTest2()throws IOException{
FileInputStream inputStream=new FileInputStream("D:/test2.txt");
//inputStream.available()返回的是文件可读的字节数
byte[] bytes=new byte[inputStream.available()];//创建字节缓冲区,大小等于文件按的大小
inputStream.read(bytes);
System.out.println(new String(bytes));
inputStream.close();
}
如果文件太大,那么创建缓冲区的时候会造成虚拟机内存耗尽,不安全。
5.3 字节流实现文件复制
代码:
/**
* 和使用字符流复制文档文件操作基本一致:
* 1,创建读和写的字节流对象。
* 2,创建字节缓冲区。
* 3,从数据读到缓冲区里面。
* 4,从缓冲区里将数据写入硬盘。
* @throws IOException
*/
static void streamCopyPicture()throws IOException{
FileInputStream inputStream=new FileInputStream("D:/view.jpg");
FileOutputStream outputStream=new FileOutputStream("E:/copy.jpg");
byte[] buffer=new byte[1024];
int len=0;
while((len=inputStream.read(buffer))!=-1){
outputStream.write(buffer,0,len);
}
inputStream.close();
outputStream.close();
}
5.4 字节流缓冲区实现文件拷贝
代码:
/**
* 字节流缓冲区实现文件拷贝
* @throws IOException
*/
static void bufferedCopy()throws IOException{
BufferedInputStream inputStream=new BufferedInputStream(new FileInputStream("D:/view.jpg"));
BufferedOutputStream outputStream=new BufferedOutputStream(new FileOutputStream("E:/copy2.jpg"));
int ch=0;
//inputStream.read()读取到的是一个字节的数据
while((ch=inputStream.read())!=-1){
outputStream.write(ch);
}
inputStream.close();
outputStream.close();
}
用法和字符缓冲区的用法基本一致。不过inputStream.read()读取到的是一个字节。
6.转换流
如果需要指定编码方式,那么就需要用到转换流,转换流可以指定编码方式。
6.1 InputStreamReader
从键盘读取数据,如果输入为over,则结束。
//转换流InputStreamReader
static void keyboardIn()throws IOException{
//inputStream从键盘录入
InputStream inputStream=System.in;
//InputStreamReader是Reader子类,转化流:将字节流转化为字符流
InputStreamReader reader=new InputStreamReader(inputStream);
//创建字符流缓冲区对象,用这个就不用创建字符数组作为缓冲区了
BufferedReader bufferedReader=new BufferedReader(reader);
String string=null;
//每次只读取一行
while((string=bufferedReader.readLine())!=null){
if(string.equals("over")){
break;
}
System.out.println(string);
}
}
6.2 OutputStreamWriter
OutputStreamWriter是Writer的子类。
以OutputStream作为构造参数。
模拟控制台输出:
{
//System.out控制台输出返回OutputStream
OutputStream outputStream=System.out;
//转化流,将字节流转化为字符流
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(outputStream);
//使用bufferd缓冲区
BufferedWriter bufferedWriter=new BufferedWriter(outputStreamWriter);
//写入一个字符串
bufferedWriter.write("zhang san");
//写入一个回车换行
bufferedWriter.newLine();
//关闭资源
bufferedWriter.close();
}
7.打印流
//获取系统信息。
Properties properties=System.getProperties();
properties.list(new PrintStream("D:/test3.txt"));
System.out.println(properties);
8. 文件对象File
8.1 文件分隔符
windows和linux下文件分隔符不同,java提供了跨平台的操作来获取文件分隔符。
String string=File.separator;
8.2 常用方法
1,创建文件:
boolean createNewFile(); 在指定位置创建文件,如果文件已经存在,则不创建,返回false。
创建成功,返回true。
File file =new File(“file.txt”);
file.createNewFile();//若创建成功,则返回true。若存在则不创建。
创建文件夹:
File mkdir=new File(“test”);
mkdir.mkdir();创建一个test文件夹(文件目录)。此方法只能创建一级目录。
File mkdirs=new File(“test\movies”);
mkdirs.mkdirs()
创建多级文件夹,test文件夹下还有movies文件夹。
2,删除文件:
boolean delete();但是如果文件在进行读写操作,删除失败,返回false。
void deleteOnExit();在程序退出时删除指定文件。
3,判断:
boolean canExecute() ; 文件是否能执行。
canRead():是否可读。
canWrite();是否可写。
boolean exists() ;文件是否存在。
boolean isDirectory() :判断当前 抽象路径File是不是文件夹(目录)
boolean isFile() :判断当前 抽象路径File是不是标准文件。
4.获取信息:
String getAbsolutePath() :返回此抽象路径名的绝对路径名形式
long length() :返回由此抽象路径名表示的文件的长度。
String getPath() :将此抽象路径名转换为一个路径名字符串。
boolean renameTo(File dest) :重新命名此抽象路径名表示的文件。
8.3 递归列出指定文件下所有的目录和文件
//列出指定文件下的文件和文件夹,包含子目录中的内容
static void showDir(File file){
System.out.println(file);
//列出该文件下所有的文件夹和文件
File[]files=file.listFiles();
for(int x=0;x<files.length;x++){//遍历
//如果列出的文件是文件夹,那么调用showDir()方法,继续列出其下面的文件和文件夹
if(files[x].isDirectory()){
showDir(files[x]);
}else {
System.out.println(files[x]);
}
}
}
- 递归必须要有跳出的条件
- 递归次数不能太多,否则会造成内存溢出。因为每调用一次方法,都会重新开辟一块内存。
- 9. java配置文件与Properties
**Properties是Hashtable的子类,具备map集合的特点,而且存储的键值对都是字符串。
它是集合中和IO技术相结合的集合容器。用来键值对形式的配置文件。**
代码1:
static void propertiesTest1(){
//创建对象
Properties properties=new Properties();
//设置键值对
properties.setProperty("name", "liang");
properties.setProperty("age", "28");
properties.setProperty("country", "China");
//得到所有字符串类型的键
Set<String>set=properties.stringPropertyNames();
//根据键对Properties进行遍历
for(String string:set){
System.out.println(string+"--"+properties.get(string));
}
}
//输出结果
age--28
name--liang
country--China
创建配置文件并用Properties读取和修改:
代码2:
/**
* Properties和IO流进行关联必须创建相关的IO流对象。
* @throws IOException
*/
static void propertiesTest2()throws IOException{
//创建读取的IO流对象,info.txt是配置文件。
FileInputStream fileInputStream=new FileInputStream("D:/info.txt");
Properties properties=new Properties();
//加载流对象,除了InputStream,还可以是Reader。
properties.load(fileInputStream);
//添加一条配置数据
properties.setProperty("hobby", "eating");
//修改配置数据后,必须使用写入流对象将修改后的数据保存到文件中。
FileOutputStream fileOutputStream=new FileOutputStream("D:/info.txt");
//将修改的信息保存到文件中,第二个参数是说明信息。除了可以使用OutputStream,还可以使用Writer。
properties.store(fileOutputStream, "第一次修改");
Set<String>set=properties.stringPropertyNames();
//根据键对Properties进行遍历
for(String string:set){
System.out.println(string+"--"+properties.get(string));
}
//关闭流资源
fileInputStream.close();
fileOutputStream.close();
}
10. 序列流
序列流,可以将多个文件中的内容合并成一个文件
/**
* 序列流,可以将多个文件中的内容合并成一个文件
* @throws IOException
*/
static void sequenceStreamTest() throws IOException{
Vector<FileInputStream>vector=new Vector<>();
//三个文件,创建三个字节输入流对象。
FileInputStream inputStream1=new FileInputStream("D:/1.txt");
FileInputStream inputStream2=new FileInputStream("D:/2.txt");
FileInputStream inputStream3=new FileInputStream("D:/3.txt");
vector.add(inputStream1);
vector.add(inputStream2);
vector.add(inputStream3);
Enumeration<FileInputStream> enumeration=vector.elements();
//构造方法参数是Enumeration对象,所以需要用到Vector。
SequenceInputStream sequenceInputStream=new SequenceInputStream(enumeration);
//创建输出流,将合并好的流进行输出。
FileOutputStream outputStream=new FileOutputStream("D:/4.txt");
//进行读写操作。
byte[] bytes=new byte[1024];
int len=0;
while((len=sequenceInputStream.read(bytes))!=-1){
outputStream.write(bytes,0,len);
}
//关闭资源
sequenceInputStream.close();
outputStream.close();
}