您的位置:首页 > 职场人生

黑马程序员—————Java基础--------IO流

2015-08-27 12:43 525 查看
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

IO流(一)

IO概述:IO(Input/Output),即输入/输出;泛指对某个设备或环境进行数据的数据或输出。

例如:对硬盘进行输入输出,对视频设备进行输入输出,对网络主机进行输入输出等。

我们可以想象,因设备或环境的不同,会有各式各样的输入输出问题与解决方案。对于输入输出问题,Java将之抽象为流对象来解决。对不同的输入输出问题,会有相应的流对象提供解决方案。

IO流:IO流用来处理不同设备间的数据传输。Java中用于操作流的对象都封装在IO包中。

IO流分类:

A:按操作数据不同:字节流和字符流

B:按数据的流向不同:输入流(读取数据)和输出流(写入数据)



这点儿注意啦:不知道有没有和我一样的,老是记反,总是觉得输入流就是往里面写入数据的,输出流才是读取数据,看过视频后终于明白了,一定要明白自己站的角度,咱们是Java程序的编写者,始终都是从某个地方读取数据,然后再写入到指定的地方。

字节流比字符流出现事的要早,而且以后对字符流搞不懂的话,永远用字节流它也肯定不会报错,因为没有字符流的时候,字节流也什么都能做。说到这儿,肯定会有人问那字符流有什么用呢?

字符流一次能读一个字符,相当于两个字节,说白了就是一个汉字,而字节流一次只能读8个字节,也就是一个字符,所以字符流的出现就是为了解决文本数据的问题。有时候为了操作的方便,我们使用字符流。

那到底什么时候使用字符流呢?
通过windows自带的记事本,能够把这个文件打开,并且里面的内容你还能够读懂,这样的文件就可以使用字符流 。否则使用字节流。

在正式了解Java中如何处理文件的输入输出之前,我们需要了解Java是如何表示一个文件的:

我们硬盘上数据最常见的方式就是以文件存在的,而文件本身有很多的属性,比如说:文件大小,是否可读啊,是否隐藏啊。那么,java为了方便操作这些文件,Java就在IO包中提供了File类对文件本身进行封装。

File类中定义了一些与平台无关的方法供我们来操作文件。例如创建、删除、重命名文件等。在Java中,目录也是用File类来进行封装的。

File对象可以作为参数传递给流对象的构造方法。

下面我们一起通过学习API,来掌握File类常见方法的使用吧~~

File既可以表示文件,也可以表示文件夹。(目录)

1)构造方法:


File(String pathname):根据指定的路径创建File对象。

File(String parent, String child):根据指定的父文件夹和子文件或者文件夹创建File对象

File(File parent, String child):根据指定的父文件夹对象和子文件或者文件夹创建File对象

在这儿写一个小的Demo来帮助记忆:

public class FileDemo {
public static void main(String[] args) {
// 方式1
File file = new File("d:\\a.txt");
File file2 = new File("d:\\aaa");

// 方式2
File file3 = new File("d:\\", "a.txt");
File file4 = new File("d:\\", "aaa");

// 方式3
File file5 = new File("d:\\");
File file6 = new File(file5, "a.txt");
File file7 = new File(file5, "aaa");
}
}


2)成员方法:

1:创建功能

创建文件:public boolean createNewFile() -- -- -- 如果指定的文件不存在,就创建。如果存在,就不创建。

创建文件夹:public boolean mkdir() -- ---- -- 创建指定的目录,如果存在,就不创建。

当且仅当已创建目录时,返回
true
;否则返回
false


public boolean mkdirs() --- -- --创建指定的目录,如果存储,就不创建。

这个时候注意,如果父目录不存在,它也会自动创建。

在这儿引用老师的一句话:你要创建什么,自己最清楚。也就是说你要调用哪个方法,你自己必须明白,如果你不明白,就会出问题的!


什么问题呢? 就是如果你明明想创建文件,却调用了创建创建文件夹的方法,最终也会创建成功,但是却是文件夹。所以大家有时候在网上看到例如.txt 结尾的,未必是文件,也有可能是文件夹。就像骑白马的不一定是王子,可能是叫花子。哈哈哈哈~~~~ 好了,下面言归正传:


绝对路径:以盘符开始的路径。

相对路径:不以盘符开始的路径。



附个小练习,帮助理解:

public class FileDemo {
public static void main(String[] args) throws IOException {
//创建文件
File file=new File("d:\\a.txt");
System.out.println("createNewFile():"+file.createNewFile()); //file.createNewFile():true

// 创建文件 忘了写路径名称了,以当前项目路径所在路径为父目录
File file1=new File("b.txt");
System.out.println("createNewFile():"+file1.createNewFile());//file1.createNewFile():true

// 创建目录
File file2=new File("ccc");
System.out.println("mkdir():"+file2.mkdir()); //mkdir():true

// 创建多级目录 如果想创建一个指定的目录或者文件,要求父目录必须存在。所以下面打印的是false
File file3=new File("bbb\\ccc");
System.out.println("mkdir():"+file3.mkdir());  //mkdir():false

// 解决方案:
File file4=new File("bbb");
File file5=new File(file4,"ccc");
System.out.println("mkdir:" + file4.mkdir());//mkdir:true
System.out.println("mkdir:" + file5.mkdir());//mkdir:true
// 但是如果目录过多,这样做就太麻烦。肿么办呢?
File file6=new File("ddd\\eee");
System.out.println("file6.mkdirs()"+file6.mkdirs());

//创建文件
File file7=new File("f.txt");
System.out.println("file7.mkdir()"+file7.mkdir());

}
}


下面是运行后的结果:



2:删除功能

public boolean delete():既可以删除文件,也可以删除文件夹。取决于你使用的对象。

删除功能比较好理解,但是有两点需要特别注意:

A:如果你删除的目录下还有内容,那么,必须先把所有内容删除完毕后,再删除目录。

B:java语言的删除不走回收站。


下面附上小练习:(接着上面的创建过的文件夹和文件,做的删除)



import java.io.File;
public class FileDelete {
public static void main(String[] args) {
// 需求:我要删除a.txt
File file = new File("b.txt");
System.out.println("delete:" + file.delete());

// 需求:我要删除aaa
File file2 = new File("ccc");
System.out.println("delete:" + file2.delete());

// 需求:我要删除bbb
File file3 = new File("bbb");
System.out.println("delete:" + file3.delete());
}
}
运行后结果为:



大家可以对比上面两次截图,可以发现,前两个删除成功,最后一个没有删除掉,这是因为bbb目录下面还有东西,必须删除所有内容后,目录bbb才能删除成功。

3:判断功能

boolean exists(): 判断file对象是否存在

boolean isFile(): 判断file对象是否是文件

boolean isDirectory(): 判断file对象是否是文件夹

boolean isAbsolute(): 判断file对象是否是绝对路径

boolean canRead(): 判断file对象是否可读

boolean canWrite(): 判断file对象是否可写

boolean isHidden(): 判断file对象是否隐藏

4:获取功能

String getAbsolutePath(): 绝对路径

String getPath(): 相对路径

String getName(): 文件名称

long length(): 文件大小,单位是字节

long lastModified(): 上次修改时间的毫秒值。

5:获取功能(特殊且重要)

public static File[] listRoots(): 列出可用的系统文件根目录

public String[] list(): 返回的是指定目录下所有文件或者文件夹的名称数组

public File[] listFiles(): 返回的是指定目录下所有文件或者文件夹对象数组


最后综上,写几个案例:1、获取指定目录下所有.mp4文件的名称。

import java.io.File;
/**
* 需求:获取指定目录下所有的.mp4文件的名称。
* 思路: 1、封装指定目录
*        2、获取指定目录下所有的文件或者文件夹File数组
*        3、遍历该对象是否是文件
*        4、判断该对象的后缀名是否是以.mp3结尾。
*/
public class FileTest {
public static void main(String[] args) {
//1、封装指定目录
File f=new File("f:\\");

// 2、获取指定目录下所有的文件或者文件夹File数组
File[] fileArray=f.listFiles();

//3、遍历File数组,获取得到每一个File对象
for(File file:fileArray){
//判断该对象是否是文件
if(file.isFile()){
String fileName=file.getName();
//判断该对象的后缀名是否是.mp3结尾的
if(fileName.endsWith(".mp3")){
System.out.println(fileName);
}
}
}
}
}


输出结果:



方法二:用文件名称过滤器改进版:

import java.io.File;
import java.io.FilenameFilter;

/**
* 获取指定目录下指定后缀的文件名称:
* 1、先获取指定目录下的所有文件或者文件夹的File数组,然后再遍历的时候判断,满足条件的就输出。
* 2、直接获取指定目录下所有满足条件的File数组,然后遍历数组即可。
*   文件名称过滤器:FilenameFilter
* 		public String[] list(FilenameFilter filter)
*/
public class FileTest1 {
public static void main(String[] args) {
//封装文件目录
File file=new File("d:\\");
//获取满足条件的数组
String[] strArray=file.list(new FilenameFilter() {

@Override
public boolean accept(File dir, String name) {
File f=new File(dir,name);// d:\我的文档
//判断文件是否以.mp3结尾
boolean flag=f.isFile();
boolean  flag1=name.endsWith(".mp3");
return flag&&flag1;
}
});
//遍历字符串数组,输出所有满足条件的目录
for(String str: strArray){
System.out.println(str);
}

}
}


2、删除指定的目录(目录里面带有目录或文件)。

import java.io.File;
/**
* 需求:删除指定目录(目录里面带有目录或文件)
* 思路:
*    1、封装目录
*    2、获取该目录下的所有文件或文件夹的File数组
*    3、遍历File数组,获取每一个File对象
*    4、判断该File对象是否为目录
*                        是:返回第二步
*                        否:删除文件
*/
public class FileDelete1 {
public static void main(String[] args) {
File file=new File("ddd");
deleteFiles(file);
}

private static void deleteFiles(File file) {
File[] fileArray=file.listFiles();
if(fileArray!=null){
for(File f:fileArray){
if(f.isDirectory()){
deleteFiles(f);
}else{
System.out.println(f.getName()+"***"+f.delete());
}
}
// 如果for循环结束,就表示目录下的文件被删除完毕。
System.out.println(file.getName()+"***"+file.delete());
}
}
}


运行结果(没刷新之前)为:



刷新之后:



介绍完File类,接下来才真正进入IO流的详细讲解啦~~

1)IO流的分类:

字节流

字节输入流 读取数据 InputStream

字节输出流 写入数据 OutputStream

字符流

字符输入流 读取数据 Reader

字节输出流 写入数据 Writer



注:本来想画个图呢,这样会更清晰,看视频上老师讲课时都会画图,帮助理解,但试了几次都不好看,算了,有机会再练练~~~


FileWriter:

下面来写一个练习来用一下:

需求:我要把一句话:"为自己加油!!! 再默默坚持一下,黑马,我马上就来了! "写入一个test.txt中。

<span style="font-size:14px;">import java.io.FileWriter;
import java.io.IOException;
/**
* 需求:我要把一句话:"为自己加油!!!  再默默坚持一下,黑马,我马上就来了! "写入一个test.txt中。
* 分析:
* 		A:由于我们是写数据,所以使用OutputStream或者Writer。
* 		B:由于我们要写入到一个文本文件中,所以最终选择了Writer。
* 通过查看API,我们发现,Writer是一个抽象类。那么,怎么办呢?
* 只能找子类使用。又由于我们是对文件操作,我们猜测了这个子类的名称是:FileWriter
*/
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符输出流对象
FileWriter fw=new FileWriter("c.txt");

/*
* <span style="color:#cc0000;">创建字符输出流对象做了几件事情? A:调用系统功能创建了文件 B:创建字符输出流对象 C:把字符输出流对象指向创建的文件</span>
*/

//调用写数据的功能
// public void write(String str)
fw.write("为自己加油!!!  再默默坚持一下,黑马,我马上就来了!");

/*
* <span style="color:#cc0000;">字符流 1字符 = 2字节 文件数据底层单位是字节,而我们现在是字符,所以它不能直接把数据写入文件。 把字符输出存储到缓冲区里面。</span>
*/

//刷新缓冲区
// public void flush()
fw.flush();
//释放资源
// public void close()
fw.close();
/*
* <span style="color:#cc0000;">为什么要close()呢?</span>
* <span style="color:#cc0000;">1:让流对象变成垃圾。</span>
* <span style="color:#cc0000;">2:通知系统去释放和文件相关的资源。</span>
*/
}
}</span>


运行后结果为:



分析一下程序:上面用红色标记的字,都是在写的过程中,遇到的问题以及有疑问的地方,老师都讲到了,觉得写在出问题的代码旁,更容易理解。

下面是通过上面的程序总结的一些笔记:

字符输出流操作步骤:

A:创建字符输出流对象

B:调用对象的写入数据方法,并刷新缓冲区

C:释放资源

问题1:为什么FileWriter没有无参构造方法?

因为写数据的时候,一定要明确写到哪里去。

问题2:flush()和close() 都有刷新功能,它们有什么区别呢?

flush():只刷新缓冲区,流对象还可以继续使用。

close() :先刷新缓冲区,再关闭流对象。流对象不可以继续被使用。

问题3:难道每次调用方法的时候,都需要刷新吗?或者说,不用刷,直接等到close() 来解决,行不行?

这两种方式都不可取。

FileWriter的追加与换行:

写入数据的方式,有5种:

write(int ch)

write(char[] chs,int index,int len)

write(char[] chs)

write(String str,int index,int len)

write(String str)

在练习的时候遇到的问题:

为什么连续两次没有换行呢? 如果想换行,怎么办呢?

因为你没让它换行,所以没有换行。那就给出换行符\n不就可以了吗 ?不行,不同的操作系统,对换行符的要求不一样:

windows:\r\n linux:\n mac:\r

而有些软件在制作的时候,为了通用,对任何换行符都是可以识别的。

在不断的往下写的时候,本来想着往里面追加,结果新写入的每次都把以前的给覆盖了,如果我想追加写入怎么办?

查API,构造的时候用带两个参数的就可以实现追加了:


public FileWriter(String fileName,boolean append)


根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

FileWriter写入数据加入异常处理(把上面的代码改进了一下):

import java.io.FileWriter;
import java.io.IOException;

/*
* 加入异常处理的代码
*/
public class FileWriterDemo4 {
public static void main(String[] args) {

FileWriter fw = null;
try {
fw = new FileWriter("c.txt");
fw.write("为自己加油!!!  再默默坚持一下,黑马,我马上就来了!");
fw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}


FileReader:

字符输入流读取数据步骤:

A:创建字符输入流对象

B:调用读取数据功能,并显示

C:释放资源

下面写一下刚看API学的时候的过程:

字符输入流读取数据方式一:一次读取一个字符

import java.io.FileReader;
import java.io.IOException;

/*
* 字符输入流读取数据步骤:
* A:创建字符输入流对象
* B:调用读取数据功能,并显示
* C:释放资源
*
* 一次读取一个字符。
*/
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
// 创建字符输入流对象
// FileReader fr = new FileReader("a.txt");
FileReader fr = new FileReader("FileWriterDemo.java");

// 调用读取数据功能,并显示
// public int read()
// int ch = fr.read();
// // System.out.println(ch);
// System.out.print((char) ch);
//
// ch = fr.read();
// // System.out.println(ch);
// System.out.print((char) ch);
//
// // read()方法读取数据返回int类型,并自动移动到下一个数据位置等待读取。
// // 我们发现数据的读取和显示操作是重复的,所以我们决定用循环改进。
// // 关键是:循环的结束条件是什么
// ch = fr.read();
// System.out.println(ch);
//
// ch = fr.read();
// System.out.println(ch);
// 通过测试,我们发现,如果数据没有了,读取的时候,将返回-1

//		int ch = fr.read();
//		while (ch != -1) {
//			System.out.print((char) ch);
//			// 重新读取一次
//			ch = fr.read();
//		}

//开发写法
int ch = 0;
while((ch=fr.read())!=-1){
System.out.print((char) ch);
}

// 释放资源
fr.close();
}
}


运行后结果:






字符输入流读取数据方式一:一次读取一个字符串








开发中的代码运行结果:






复制文本文件:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
* 需求:我要把项目路径下的FileWriterDemo.java复制到f:\\Copy.java中
* 分析:
*    数据源:
*        读取数据:
* 		  FileWriterDemo.java	-- Reader -- FileReader
*    目的地:
*        写入数据:
* 		f:\\Copy.java	-- Writer -- FileWriter
* 下面我用两种方式来做:
*/
public class CopyFileDmeo {
public static void main(String[] args) throws IOException {
//封装数据源
FileReader fr=new FileReader("E:/JavaSE-2015/StringDemo/src/cn/itcast02/ExceptionDemo.java");
//封装目的地
FileWriter fw=new FileWriter("f:\\Copy.java");

//读取数据
//方式一:一次读取一个字符
//	  int ch=0;
//	  while((ch=fr.read())!=0){
//		  fw.write(ch);
//		  fw.flush();
//	  }
//方式二:一次读取多个字符
char[] chs=new char[1024];
int len=0;
while((len=fr.read(chs))!=-1){
fw.write(chs,0,len);
}

fw.close();
fr.close();
}
}
运行结果:



先到这儿吧,东西太多了,有些理解的不对的地方,真诚地希望大家帮我指正出来,谢谢!!!

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流!
-------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: