Java对数据的操作是通过流的方式进行的
IO流用来处理设备之间的数据传输,Java用语数据流的对象都在IO包里面,流按照操作数据分为两种:
字节流InPutStream、OutPutStream和字符流Reader、Writer
字符流与字节流的区别是什么?
字符流在读取时,在读取完字节数据之后会继续查表,而文字有特定的编码格式,
所以读取文本文件要使用字符流,而要读取媒体文件要使用字节流
Java的垃圾回收机制只针对堆内存中的对象,不回收物理内存,所以我们需要在finally里面对流进行关闭
记住;如果要操作文字数据,建议优先考虑字符流。
而且要将数据从内存写到硬盘上,要使用字符流中的输出流。Writer
硬盘的数据基本体现是文件。 希望找到一个可以操作文件的Writer.
File:文件和目录路径名的抽象表示形式
//创建一个可以往文件中写入字符数据的字符输出流对象。
/*
* 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)。
*
* 如果文件不存在,则会自动创建。
* 如果文件存在,则会被覆盖。
*
* 如果构造函数中加入true,可以实现对文件进行续写!
*/
FileWriter fw = new FileWriter("demo.txt",true);
/*
* 调用Writer对象中的write(string)方法,写入数据。
*
* 其实数据写入到临时存储缓冲区中。
*
*/
fw.write("abcde"+LINE_SEPARATOR+"hahaha");
// fw.write("xixi");
/*
* 进行刷新,将数据直接写到目的地中。
*/
// fw.flush();
/*
* 关闭流,关闭资源。在关闭前会先调用flush刷新缓冲中的数据到目的地。
*/
fw.close();
}
FileWriter:能在已有的目录(文件夹)下创建文件,但是不能创建目录也就是文件夹
如何处理这段程序的异常异常。
FileWriter fw = new FileWriter("demo.txt");创建失败
根据给定的 File 对象构造一个 FileWriter 对象。如果第二个参数为 true,
则将字节写入文件末尾处,而不是写入文件开始处。
为什么需要抛出异常?或者try()catch()异常?
IOException - 如果该文件存在,但它是一个目录,而不是一个常规文件;或者该
文件不存在,但无法创建它;抑或因为其他某些原因而无法打开它,都会导致异常
fw.write("abcde" + LINE_SEPARATOR + "hahaha");输入失败
fw.close();关闭失败
FileWriter fw = null;try {
fw = new FileWriter("k:\\demo.txt");
fw.write("abcde" + LINE_SEPARATOR + "hahaha");
} catch (IOException e) {
System.out.println(e.toString());
} finally {
if (fw != null)
try {
fw.close();
} catch (IOException e) {
// code....
throw new RuntimeException("关闭失败");
}
}
字符流:FileReader 建立一个流对象将一个已存在的文件加载进流
Reader:注意有Reader的都是读取方法所以其必须有已存在的读取对象。
需求:读取一个文本文件。将读取到的字符打印到控制台
1,创建读取字符数据的流对象。FileReader
FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream。
在创建读取流对象时,必须要明确被读取的文件。一定要确定该文件是存在的。
可以理解为:
用一个读取流关联一个已存在文件。
read() 读取单个字符,一次读一个。
使用 read(char[])读取文本文件数据。
public int read(char[] cbuf,int offset,int length)
throws IOException
将字符读入数组中的某一部分。
Offset:起始位置。 Length: 读取长度 ,读取时包含首不包含尾。
返回:
注意:读取的字符数,返回每次读取的字符数,如有一个长度为5的源文件,
定义一个长度为3的数组,则第一次返回的是3,第二次返回2,第三次返回-1。
抛出:
IOException - 如果发生 I/O 错误
FileReader fr = new FileReader("demo.txt");
如何使用两种方法读取文本文件数据,以及每一种读取方法如何实现,以及其优点
/*
* 使用read(char[])读取文本文件数据。
*
* 先创建字符数组。
*/
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
/*
int num = fr.read(buf);//将读取到的字符存储到数组中。
System.out.println(num+""):
需求:将c盘的一个文本文件复制到d盘。
思路:
* 1,需要读取源,
* 2,将读到的源数据写入到目的地。
* 3,既然是操作文本数据,使用字符流。
第一种方法:
//1,读取一个已有的文本文件,使用字符读取流和文件相关联。
FileReader fr = new FileReader("IO流_2.txt");
//2,创建一个目的,用于存储读到数据。
FileWriter fw = new FileWriter("copytext_1.txt");
//3,频繁的读写操作。
int ch = 0;
while((ch=fr.read())!=-1){每读取一次
fw.write(ch);就存储一次
//4,关闭流资源。
fw.close();
fr.close();
---------------------------------------------------------------------
字符流缓冲区:BufferedWriter BufferedReader:
缓冲区的例子就像之前读取时创建的数组:char[] buf
FileWriter fw = new FileWriter("buf.txt");
新建一个缓冲区,并且接受一个文件,注意缓冲区必须接收流文件对象,
否则缓冲区没有意义。
public class BufferedWriter extends Writer
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的
高效写入。
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了
缓冲区的作用:
为了提高写入的效率。使用了字符流的缓冲区。
创建了一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
创建一个方法,定义一个常量,用于获取所在系统的换行符,这种方法在哪里都通用。
BufferedReader:
方法:
readLine() 读取一个文本行。( 以回车换行符为一行
新建一个读取缓冲区,接收一个已有文件
BufferedReader bufr = new BufferedReader(fr);
bufr:readLine();字符流缓冲区对象的方法,是从字符流中读取的数据
FileReader fr = new FileReader("buf.txt");
//新建一个流对象,并且接受一个已有的文件buf.txt文件。
BufferedReader bufr = new BufferedReader(fr);
//新见一个缓冲区对象,并且接收流对象fr的内容。
FileWriter fw = new FileWriter("buf_copy.txt");
//创建流对象,并且建立数据存储文件buf_copy.txt
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;//定义一个string变量,赋值为空。
while((line=bufr.readLine())!=null){//当变量不为空时,继续执行
bufw.write(line);//这里的读和写都是针对的缓冲区对象。
bufw.newLine();
bufw.flush();
------------------------------------------------------------------------------------
装饰设计模式:
对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。
装饰和继承都能实现一样的特点:进行功能的扩展增强。
有什么区别呢?
首先有一个继承体系。
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体。
想要对操作的动作进行效率的提高。
按照面向对象,可以通过继承对具体的进行功能的扩展。
效率提高需要加入缓冲技术。
Writer
|--TextWriter:用于操作文本
|--BufferTextWriter:加入了缓冲技术的操作文本的对象。
|--MediaWriter:用于操作媒体。
|--BufferMediaWriter:
到这里就哦了。但是这样做好像并不理想。
如果这个体系进行功能扩展,有多了流对象。
那么这个流要提高效率,是不是也要产生子类呢?是。这时就会发现只为提高功能,进行的继承,
导致继承体系越来越臃肿。不够灵活。
重新思考这个问题?
既然加入的都是同一种技术--缓冲。
前一种是让缓冲和具体的对象相结合。
可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲关联。
class Buffer{
Buffer(TextWriter w)
{}
Buffer(MediaWirter w)
{
}
}
class BufferWriter extends Writer{
BufferWriter(Writer w)
{
}
}
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体。
|--BufferWriter:用于提高效率。
装饰比继承灵活。
特点:装饰类和被装饰类都必须所属同一个接口或者父类。
----------------------------------------------------------------
转换流:
InputStreamReader :字节到字符的桥梁。解码。
OutputStreamWriter:字符到字节的桥梁。编码。
字符流中有字符装饰流类,而字节流没有,
所以如果将字节流转换成字符流,就可以使用字符流的装饰设计模式。
字节流加上编码表就是字符流。
将字节转成字符的桥梁。转换流。
InputStreamReader isr = new InputStreamReader(in);
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的
charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,
或者可以接受平台默认的字符集。
InputStreamReader(InputStream in) 将字节流转换成字符流。
创建一个使用默认字符集的 InputStreamReader。
字符与字节流的区别就是:
比如:一个中文“你”,字节流会度两次,返回两个对应值,例:197、 230、
而字符流只会对一次,其实字符流调用的还是字节流的方法,但是当他读取到两个值之后,
会拿着这两个值去查表,然后返回对应的一个值例:20325.
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset
将要写入流中的字符编码成字节。
例子:传递情报时,将文字变成电报的码,就叫编码,对方接受到了之后将电报码
变成文字就叫解码。
流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想要知道开发时用到哪些对象。只要通过四个明确即可。
1,明确源和目的(汇)
源:InputStream Reader
目的:OutputStream Writer
2,明确数据是否是纯文本数据。
源:是纯文本:Reader
否:InputStream
目的:是纯文本 Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。
3,明确具体的设备。
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4,是否需要其他额外功能。
1,是否需要高效(缓冲区);
是,就加上buffer.
2,转换。
需求1:复制一个文本文件。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本?
是!
源:Reader
目的:Writer
3,明确具体设备。
源:
硬盘:File
目的:
硬盘:File
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
4,需要额外功能吗?
需要,需要高效。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
================================================
需求2:读取键盘录入信息,并写入到一个文件中。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确设备
源:
键盘。System.in
目的:
硬盘。File
InputStream in = System.in;
FileWriter fw = new FileWriter("b.txt");
这样做可以完成,但是麻烦。将读取的字节数据转成字符串。再由字符流操作。
4,需要额外功能吗?
需要。转换。 将字节流转成字符流。因为名确的源是Reader,这样操作文本数据做便捷。
所以要将已有的字节流转成字符流。使用字节-->字符 。InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("b.txt");
还需要功能吗?
需要:想高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
===================================================
需求3:将一个文本文件数据显示在控制台上。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确具体设备
源:
硬盘:File
目的:
控制台:System.out
FileReader fr = new FileReader("a.txt");
OutputStream out = System.out;//PrintStream
4,需要额外功能吗?
需要,转换。
FileReader fr= new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(System.out);
需要,高效。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
================================================================
需求4:读取键盘录入数据,显示在控制台上。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确设备。
源:
键盘:System.in
目的:
控制台:System.out
InputStream in = System.in;
OutputStream out = System.out;
4,明确额外功能?
需要转换,因为都是字节流,但是操作的却是文本数据。
所以使用字符流操作起来更为便捷。
InputStreamReader isr = new InputStreamReader(System.in);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
为了将其高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
============================================================
5,将一个中文字符串数据按照指定的编码表写入到一个文本文件中.
1,目的。OutputStream,Writer
2,是纯文本,Writer。
3,设备:硬盘File
FileWriter fw = new FileWriter("a.txt");
fw.write("你好");
注意:既然需求中已经明确了指定编码表的动作。
那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表。
只能使用其父类。OutputStreamWriter.
OutputStreamWriter接收一个字节输出流对象,既然是操作文件,那么该对象应该是FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName);
需要高效吗?
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));
什么时候使用转换流呢?
1,源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁。
提高对文本操作的便捷。
2,一旦操作文本涉及到具体的指定编码表时,必须使用转换流 。
要注意字符流需要刷新,字节流不需要刷新。
字符流与字节流的相互转换的原理图:
第一步:从控制台输入的字节流开始,先转换成字符流,在进行高效处理
从而实现读取字符数据。
第二步:将字符数据写入缓冲区,再转成字节流,最后输出到控制台
这就是从控制台输入到控制台输出的整个过程。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
键盘录入方法的最佳书写
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in))
键盘输出方法的最佳书写
BufferedWriter bufw =new BufferedWriter(new OutputStreamWriter(System.out))
----------------------------------------------------------------------------------------------
File :提供了将文件所在目录或者路径封装成对象的方法。文件和目录路径名的
抽象表示形式。
File类的常用方法:
boolean b = dir.mkdir();//make directory创建单级目录。
System.out.println("b="+b);
dir.mkdirs();//创建多级目录
创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
注意,此操作失败时也可能已经成功地创建了一部分必需的父目录。
Char pathSeparatorChar
与系统有关的路径分隔符。此字段被初始为包含系统属性 path.separator 值
的第一个字符。此字符用于分隔以路径列表 形式给定的文件序列中文件名。
File(String parent, String child)
File f1 = new File("c:\\a.txt");
File f2 = new File("c:\\","a.txt")
*根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。File f4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt")
Separator():与系统有关的默认名称分隔符,为了方便,它被表示为一个
字符串。这里的名称分隔符就相当于之前的“\\”,但是这个方法可以获取
任意所在系统的分隔符。
详细方法介绍见:
E:\Java\java\day22e\src\cn\itcast\io\p2\file\demo FileDemo文件
File对象的常见方法。
1,获取。
1.1 获取文件名称1.2 获取文件路径1.3 获取文件大小1.4 获取文件修改时间。
2,创建与删除。
3,判断。
4, 重命名