- 浏览: 3192 次
文章分类
最新评论
第一讲 什么是IO? IO分类?
1、何为流:流是JAVA中的一个重要机制,通过流我们能自由地控制文件,内存,IO设备的数据输入和输出。
2、Java中流的体系:Java用于操作流的对象都在java.io包中。
3、流的分类
1)按流的方向分为:输入流和输出流
2)按流处理数据单位的不同分为:字节流和字符流
3)按流的功能不同分为:节点流和处理流
4、IO流的四大抽象类:
字符流:Reader、Writer
字节流:InputStream、OutputStream
第二讲 Reader、Writer字符流
一、字符流
字符流使用系统默认的编码表处理文字数据。
二、Reader、Writer本身是抽象类、是所有字符输入流、输出流的父类。其定义了所有字符流的标准、和一些必须具有的基本方法。
三、字符流的读写
1、Writer流步骤(会发生IOException异常,所以在整个步骤中,需要对IO异常进行try处理。)
1)创建FileWriter对象。构造方法可以接收String路径、File对象作为参数。FileWriter(String fileName) 创建对象时必须要明确被操作的文件。若目录下如果已有同名文件,则覆盖。不想覆盖原文件,可以用FileWriter(String fileName, boolean append) 构造方法。如果指定的位置不存在,就会发生IOException异常。
2)调用write方法,将数据写入到流中。
3)调用flush()方法,刷新该流的缓冲,将数据刷新到目的地中。flush()方法调用OS功能完成数据的书写,使用系统资源后,一定要关闭资源。
4)调用close()方法,关闭流资源。关闭前会刷新一次内部的缓冲数据到目的文件中。
2、Reader流步骤
1)创建对象关联指定文件。若指定文件不存在,会发生异常FileNotFoundException。
2)read()或者 read(char[] cbuf)。读单个字符或通过字符数组进行读取。
3)close()关闭流资源。
四、BufferedReader和BufferedWriter
1、目的:提高效率。缓冲各个字符,从而实现字符、数组和行的高效读写。
2、原理:封装了数组,将数据存入,再一次性取出。
3、BufferedWriter的步骤:
1)创建一个FileWriter 对象。
FileWriter fw=new FileWriter("a.txt");
2)为了提高字符写入流效率。加入缓冲技术。
BufferedWriter bufw =new BufferedWriter(fw);
3)调用write方法写入数据到指定文件
如:bufw.write("aaabbbccc");
刷新缓冲区 bufw.flush();
4)关闭缓冲区,就是关闭缓冲区中的流对象。
如: bufw.close();
常用方法:数据换行。bufw.newLine();
4、BufferedReader的步骤:
1)创建一个FileReader 对象。
如: FileReader fr=new FileReader("a.txt");
2)为了提高效率。加入缓冲技术。
如: BufferedReader bufr=new BufferedReader(fr);
3)调用readLine方法按行读取
如: String s=bufr.readLine();
4)关闭流资源
如: bufr.close();、
常用方法:readLine方法,返回null时表示读到文件末尾。
5、自定义BufferedReader:
原理:
根据BufferedReader类中readLine()的原理,自定义一个类中包含相同功能的方法
步骤:
a、初始化自定义的类,加入流对象。
b、定义一个临时容器,原BufferedReader封装的是字符数组,此类中可定义一个StringBuilder的容器,最终可实现字符串的提取。
6、LineNumberReader
BufferedReader中有个直接的子类LineNumberReader,其中有特有的方法获取和设置行号:
setLineNumber();//设置初始行号
getLineNumber();//获取行号
四、装饰设计模式
1、目的
对已有对象进行功能增强。可定义类,将已有对象传入,基于已有对象的功能,并提供加强功能。自定义的该类称之为装饰类。
2、特点
装饰类通常都会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
3、装饰和继承的区别:
1)装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。
2)装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。
3)从继承结构转为组合结构。
注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。
示例:上面讲到的MyBufferedReader的例子就是最好的装饰设计模式的例子。
----------------------------------------------------------------------------------
第三讲 字节流
一、InputStream、OutputStream
1、字符流只能操作纯文本文件,字节流可以操作文本、多媒体等各种文件。
2、字节流对象可直接将数据写入到文件中,字符流操作数据要在字节和字符之间进行转换,字节流直接操作字节,所以不需要flush操作。
3、InputStream特有方法:int available();//返回文件中的字节个数
二、BufferedInputStream、BufferedOutputStream
1、目的: 提高读写效率。
2、特点:
read():会将字节byte型值提升为int型值
write():会将int型强转为byte型,即保留二进制数(&0xff)的最后八位。
三、自定义读取字节流缓冲区
需求:根据字节流缓冲区的原理,自定义一个字节流缓冲区。
注意:
1、字节流的读一个字节的read方法为什么返回值类型不是byte,而是int?
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1;-1是读取结束的标志。数据还没有读完,返回-1。为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。而在写入数据时,只写该int类型数据的最低8位。byte类型的-1提升为int类型时还是-1。原因:因为在8个1前面补的全是1导致的,如果在8个1前面补0,即可以保留原字节数据不变,又可以避免-1的出现。将byte型数据&0xff即255即可。
__________________________________________________________________
第四讲 流操作规律
一、键盘录入
1、System.in与out
System.in:标准输入设备,键盘。类型是InputStream.
Ssytem.out:标准的输出设备,控制台。类型是PrintStream是OutputStream的子类FilterOutputStream的子类。
2、整行录入
当使用System.in进行键盘录入时,只能一个字节一个字节录入。为了提高效率,可以自定义一个数组将一行字节进行存储。当一行录入完毕,再处理整行数据。这就是
BufferedReader类中readLine()的原理。
3、转换流
3.1 InputStreamReader将字节流通向字符流
a、获取键盘录入对象。
InputStream in=System.in;
b、将字节流对象转成字符流对象,使用转换流。
InputStreamReaderisr=new InputStreamReader(in);
c、为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
//键盘录入最常见写法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
3.2 OutputStreamWriter字符流通向字节流
步骤和InputStreamReader转换流一样。
二、确定用哪种流对象
4.三步完成:
4.1 明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
4.2 操作的数据是否是纯文本。
是:字符流
否:字节流
4.3 当体系明确后,再明确要使用哪个具体的对象。通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
5、规律体现
5.1 将一个文本文件中数据存储到另一个文件中。复制文件。
1)源:因为是源,所以使用读取流:InputStream和Reader
明确体系:是否操作文本:是,Reader
明确设备:Reader体系中可以操作文件的对象是FileReader
是否需要提高效率:是,加入Reader体系中缓冲区 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
2)目的:输出流:OutputStream和Writer
明确体系:是否操作文本:是,Writer
明确设备:Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是,加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。
1)源:输入流,InputStream和Reader
是否是文本?否,InputStream
源设备:硬盘上的一个文件。InputSteam体系中可以操作文件的对象是FileInputSteam
是否需要提供效率:是,BufferedInputStream
BufferedInputSteambis=new BufferedInputStream(newFileInputStream("c:/users/asus/desktop/1.jpg"));
2)目的:输出流,OutputStream和Writer
是否是文本?否,OutputStream
源设备:硬盘上的文件,FileOutputStream
是否需要提高效率:是,加入BufferedOutputStream
BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream("c:/users/asus/desktop/2.jpg"));
5.2 需求:将键盘录入的数据保存到一个文件中。
1)源:InputStream和Reader
是不是纯文本?是,Reader
设备:键盘。对应的对象是System.in。——为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成
Reader。用Reader体系中转换流,InputStreamReader
InputStreamReaderisr = new InputStreamReader(System.in);
需要提高效率吗?需要,BufferedReader
BufferedReaderbufr = new BufferedReader(isr);
2)目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = newFileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
5.3 扩展:想要把录入的数据按照指定的编码表(UTF-8)(默认编码表是GBK),将数据存到文件中。
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘上的一个文件。使用 FileWriter。——但是FileWriter是使用的默认编码表:GBK。而存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。
该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流:FileOutputStream
OutputStreamWriter osw =new OutputStreamWriter(newFileOutputStream("d.txt"),"UTF-8");
需要高效吗?需要,BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
记住:
转换流什么使用?
字符和字节之间的桥梁。通常,涉及到字符编码转换时,需要用到转换流。
练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
1)源:InputStream、Reader
是文本?是:Reader
设备:硬盘。上的文件:FileReader
是否需要提高效率?是:BufferedReader
BufferedReader br=new BufferedReader(newFileReader("1.txt"));
2)目的:OutputStream Writer
是文本?是:Writer
设备:控制台。对应对象System.out。由于System.out对应的是字节流,所以利用OutputSteamWriter转换流
是否提高效率?是:BufferedWriter
BufferedWriter bw =new BufferedWriter(newOutputStreamWriter(system.out));
---------------------------------------------------------------------
第一讲 File类
一、概述
1、File类:文件和目录路径名的抽象表现形式
2、特点:
1)用来将文件或目录封装成对象
2)方便于对文件与目录的属性信息进行操作
3)File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变
4)File对象可以作为参数传递给流的构造函数
二、File对象创建
方式一:
File f =new File("a.txt");
将a.txt封装成File对象。可以将已有的和未出现的文件或者文件夹封装成对象。
方式二:
File f2=newFile("c:\\abc","b.txt");
将文件所在目录路径和文件一起传入,指定文件路径。
方式三:
File d=new File("c:\\abc");
File f3=new File(d,"c.txt");
将文件目录路径封装成对象。再创建文件对象。降低了文件于父目录的关联性。
小知识:
File.separator表示目录分隔符,可以跨平台使用。相当于路径中的“\”(双斜杠\\在windows中表示表示转义后的分隔符,但是在linux系统中就不是)。
三、File类的常见方法
1、创建
boolean createNewFile();
//在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立就创建文件。而且文件已经存在,会覆盖。
boolean mkdir();//创建文件夹,只能创建一级文件夹
例:
File dir=new File("abc");
dir.mkdir();//创建abc这个文件夹
boolean mkdirs();//创建多级文件夹
2、删除
boolean delete();
//删除文件或目录。文件存在,返回true;文件不存在或者正在被执行,返回false。
void deleteOnExit();//在程序退出时删除指定文件
3、判断
boolean canExecute();//是否是可执行文件
boolean exists();//文件是否存在
boolean isFile();//是否是文件
boolean isDirectory();//是否是文件夹
boolean isHidden();//是否是隐藏文件
boolean isAbsolute();//文件是否是绝对路径
记住:在判断文件对象是否是文件或者目录时,必须要判断该文件对象封装的内容是否存在。通过exists判断。
4、获取信息
String getName();//获取文件名
String getPath();
//获取文件的相对路径(即创建的对象传入的参数是什么就获取到什么)
String getParent();
//获取文件父目录。返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。如果相对路径中有上一层目录,那么该目录就是返回结果。
String getAbsolutePath();//获取文件的绝对路径
long lastModified();//返回文件最后一次被修改的时间
long length();//返回文件长度
5、列出文件及文件过滤
static File[] listRoots();//列出可用的文件系统根目录,即系统盘符
String[] list();
//列出当前目录下所有文件,包括隐藏。调用list方法的file对象必须是封装了一个目录。该目录还必须存在。
String[] list(FilenameFilter filter);
//返回一个字符串数组,获取目录中满足指定过滤器的文件或目录。
//FilenameFilter:文件名过滤器,是一个接口,其中包含一个方法,accept(Filedir,String name),返回的是boolean型,对不符合条件的文件过滤掉。
File[] listFiles();//返回一个抽象路径名数组,获取当前文件夹下的所有文件和文件夹
File[] ListFiles(FilenameFilterfilter);//返回抽象路径名数组,获取目录中满足指定过滤器的文件或目录。
四、递归
1、定义
当函数内每一次循环还可以调用本功能来实现,也就是函数自身调用自身。这种表现形式,或者编程手法,称为递归。
2、递归注意事项
a、限定条件。是来结束循环调用,否则是死循环。
b、注意递归的次数,尽量避免内存溢出。因为每次调用自身的时候都会先执行下一次调用自己的方法,所以会不断在栈内存中开辟新空间,次数过多,会导致内存溢出。
第二讲 Properties类
一、概述
1、Properties是Hashtable的子类,它具备Map集合的特点。而且它里面还有存储的键值对,都是字符串,无泛型定义。是集合中和IO技术相结合的集合容器。
2、特点:
1)可用于键值对形式的配置文件
2)在加载时,需要数据有固定的格式,常用的是:键=值
二、特有方法
1、设置
Object setProperty(String key,String value);
//设置键和值,调用Hashtable的方法put
2、获取
String getProperty(String key);
//指定key搜索value
Set<String> stringPropertyName();
//返回属性列表的键集,存入Set集合
3、加载流和存入流
void load(InputStream ism);
//从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void load(Reader reader);
//从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void list(PrintStream out);//将属性列表输出到指定的输出流
void store(OutputStreamout,String comments);
//对应load(InputStream )将属性列表(键值对)写入输出流。comments属性列表的描述。
void store(Writerwriter, String comments);
//对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。
示例
第三讲 打印流
一、概述
1、打印流包括:PrintStream和PrintWriter
2、该流提供了打印方法,可将各种类型的数据都原样打印。
二、字节打印流:PrintStream
构造方法中可接收的参数类型:
1、File对象。File
2、字符串路径:String
3、字符输出流:OutputStream
三、字符串打印流:PrintWriter
构造方法中可接受的参数类型
1、File对象:File
2、字符串路径:String
3、字节输出流:OutputStream
4、字符输出流:Writer
示例
第四讲 序列流
一、概述
1、SequenceInputStream对多个流进行合并。也被称为合并流。
2、常用构造函数
SequenceInputStream(Enumeration<?extends FileInputStream> e)
二、常见合并多个流文件步骤
1、创建集合,并将流对象添加进集合
2、创建Enumeration对象,将集合元素加入。
3、创建SequenceInputStream对象,合并流对象
4、创建写入流对象,FileOutputStream关联写入文件
5、利用SequenceInputStream对象和FileOutputStream对象读数据进行反复读写操作。
第五讲 对象的序列化
目的:将一个具体的对象进行持久化,写入到硬盘上。
注意:静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
如何将非静态的数据不进行序列化?
用transient 关键字修饰此变量即可。
Serializable:用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运算获取的。如果不需要自动获取一个uid,可以在类中手动指定一个名称为serialVersionUID id号。依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显式的UID的指定。
第六讲 管道流
管道读取流和管道写入流可以像管道一样对接上,管道读取流可以读取管道写入流写入的数据。
注意:需要加入多线程技术,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,没有数据的read方法会让线程等待。
第七讲 RandomAccessFile
特点:
1:该对象即可读取,又可写入。
2:该对象中的定义了一个大型的byte数组,通过定义指针来操作这个数组。
3:可以通过该对象的getFilePointer()获取指针的位置,通过seek()方法设置指针的位置。
4:该对象操作的源和目的必须是文件。
5:其实该对象内部封装了字节读取流和字节写入流。
注意:实现随机访问,最好是数据有规律。
第八讲 以流的读写思想来操作数组
ByteArrayInputStream:源:内存
ByteArrayOutputStream:目的:内存。
这两个流对象不涉及底层资源调用,操作的都是内存中数组,所以不需要关闭。
直接操作字节数组就可以了,为什么还要把数组封装到流对象中呢?
因为数组本身没有方法,只有一个length属性。为了便于数组的操作,将数组进行封装,对外提供方法操作数组中的元素。
第七讲 Encoding
gbk编码,一个汉字占2个字节
utf-8编码,一个汉字占3个字节
联通这两个字符的特殊性
联通----用gbk编码的二进制四个字节数据为:
11000001
10101010
11001101
10101000
恰恰符合utf-8中 110 10 110 10打头的字符编码格式,notepad.exe在解码时会默认采用utf-8解码,导致解码出错。
1、何为流:流是JAVA中的一个重要机制,通过流我们能自由地控制文件,内存,IO设备的数据输入和输出。
2、Java中流的体系:Java用于操作流的对象都在java.io包中。
3、流的分类
1)按流的方向分为:输入流和输出流
2)按流处理数据单位的不同分为:字节流和字符流
3)按流的功能不同分为:节点流和处理流
4、IO流的四大抽象类:
字符流:Reader、Writer
字节流:InputStream、OutputStream
第二讲 Reader、Writer字符流
一、字符流
字符流使用系统默认的编码表处理文字数据。
二、Reader、Writer本身是抽象类、是所有字符输入流、输出流的父类。其定义了所有字符流的标准、和一些必须具有的基本方法。
三、字符流的读写
1、Writer流步骤(会发生IOException异常,所以在整个步骤中,需要对IO异常进行try处理。)
1)创建FileWriter对象。构造方法可以接收String路径、File对象作为参数。FileWriter(String fileName) 创建对象时必须要明确被操作的文件。若目录下如果已有同名文件,则覆盖。不想覆盖原文件,可以用FileWriter(String fileName, boolean append) 构造方法。如果指定的位置不存在,就会发生IOException异常。
2)调用write方法,将数据写入到流中。
3)调用flush()方法,刷新该流的缓冲,将数据刷新到目的地中。flush()方法调用OS功能完成数据的书写,使用系统资源后,一定要关闭资源。
4)调用close()方法,关闭流资源。关闭前会刷新一次内部的缓冲数据到目的文件中。
2、Reader流步骤
1)创建对象关联指定文件。若指定文件不存在,会发生异常FileNotFoundException。
2)read()或者 read(char[] cbuf)。读单个字符或通过字符数组进行读取。
3)close()关闭流资源。
/* DEMO:示例FileWriter、FileReader操作步骤 功能:文本文件的拷贝 需求:文本文件复制 步骤: 1、在e盘创建一个文件。用于存储c盘文件中的数据。 2、定义读取流和c盘文件关联。 3、通过不断的读写完成数据存储。 4、关闭资源。 */ import java.io.*; class ReaderWriterCopy { public static void main(String[] args) { copy_singleCharReeadWrite(); // copy_arrayCharReadWrite(); } // 一个字符一个字符复制,每个字符的读写都会调用OS系统资源 public static void copy_singleCharReeadWrite() { FileWriter fw = null; FileReader fr = null; try { // 关联读取和写入的文件 fw = new FileWriter("E:\\IO_COPY.TXT"); fr = new FileReader("E:\\IO.TXT"); int ch = 0; while ((ch = fr.read()) != -1) { fw.write(ch);// 每个字符的读写都会调用OS系统资源 } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { if (fr != null) try { fr.close(); } catch (IOException e) { throw new RuntimeException("关闭FileReader失败"); } if (fw != null) try { fw.close(); } catch (IOException e) { throw new RuntimeException("关闭FileWriter失败"); } } } // 每次读写1024字节进行复制 public static void copy_arrayCharReadWrite() { FileWriter fw = null; FileReader fr = null; try { // 关联读取和写入的文件 fw = new FileWriter("E:\\IO_COPY.TXT"); fr = new FileReader("E:\\IO.TXT"); char[] arr = new char[1024]; int len = 0; while ((len = fr.read(arr)) != -1) { fw.write(arr, 0, len);// 每次读写len个字节 } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { try { if (fr != null) fr.close(); } catch (IOException e) { throw new RuntimeException("关闭FileReader失败"); } finally { if (fw != null) try { fw.close(); } catch (IOException e) { throw new RuntimeException("关闭FileWriter失败"); } } } } }
四、BufferedReader和BufferedWriter
1、目的:提高效率。缓冲各个字符,从而实现字符、数组和行的高效读写。
2、原理:封装了数组,将数据存入,再一次性取出。
3、BufferedWriter的步骤:
1)创建一个FileWriter 对象。
FileWriter fw=new FileWriter("a.txt");
2)为了提高字符写入流效率。加入缓冲技术。
BufferedWriter bufw =new BufferedWriter(fw);
3)调用write方法写入数据到指定文件
如:bufw.write("aaabbbccc");
刷新缓冲区 bufw.flush();
4)关闭缓冲区,就是关闭缓冲区中的流对象。
如: bufw.close();
常用方法:数据换行。bufw.newLine();
4、BufferedReader的步骤:
1)创建一个FileReader 对象。
如: FileReader fr=new FileReader("a.txt");
2)为了提高效率。加入缓冲技术。
如: BufferedReader bufr=new BufferedReader(fr);
3)调用readLine方法按行读取
如: String s=bufr.readLine();
4)关闭流资源
如: bufr.close();、
常用方法:readLine方法,返回null时表示读到文件末尾。
/* DEMO:练习BufferedReader、BufferedWriter 功能:复制一个文本文件。 */ import java.io.*; class ReaderWriteCopy { public static void main(String[] args) { BufferedWriter bfw = null; BufferedReader bfr = null; try { bfr = new BufferedReader(new FileReader("io.txt")); bfw = new BufferedWriter(new FileWriter("io_copy.txt")); // 按行取出 String line = null; while ((line = bfr.readLine()) != null) { bfw.write(line); bfw.newLine(); bfw.flush();// 别忘记flush } } catch (IOException e) { throw new RuntimeException("文件copy失败"); } finally { if (bfw != null) try { bfw.close();// 关闭 } catch (IOException e) { throw new RuntimeException("写入流关闭失败"); } if (bfr != null) try { bfr.close();// 关闭读取流 } catch (IOException e) { throw new RuntimeException("读取流关闭失败"); } } } }
5、自定义BufferedReader:
原理:
根据BufferedReader类中readLine()的原理,自定义一个类中包含相同功能的方法
步骤:
a、初始化自定义的类,加入流对象。
b、定义一个临时容器,原BufferedReader封装的是字符数组,此类中可定义一个StringBuilder的容器,最终可实现字符串的提取。
/* 需求:模拟BufferedReader写一个自己的MyBufferedReader 实现readLine方法 */ import java.io.*; class MyBufferedReader extends Reader { private Reader r;// 持有一个流对象 MyBufferedReader(Reader 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 int read(char[] cbuf, int off, int len) throws IOException { return r.read(cbuf, off, len); } // 复写父类的close方法 public void close() throws IOException { r.close(); } } // 测试MyBufferedReader class MyBufferedReaderDemo { public static void main(String[] args) { MyBufferedReader mbr = null; try { mbr = new MyBufferedReader(new FileReader("E:\\io.txt")); String line = null; while((line = mbr.myReadLine()) != null) { System.out.println(line); } } catch (IOException e) { throw new RuntimeException("读取数据失败"); } finally { try { if (mbr != null) mbr.close(); } catch (IOException e) { throw new RuntimeException("MyBufferedReader失败"); } } } }
6、LineNumberReader
BufferedReader中有个直接的子类LineNumberReader,其中有特有的方法获取和设置行号:
setLineNumber();//设置初始行号
getLineNumber();//获取行号
import java.io.*; /* 需求:利用LineNumberReader的特有方法去设置和获取文件中数据的行号 */ class LineNumberReaderDemo { public static void main(String[] args) { LineNumberReader lnr=null; try { lnr=new LineNumberReader(new FileReader("io.txt")); lnr.setLineNumber(100);//设置开始行号 String line=null; while((line=lnr.readLine())!=null) { System.out.println(lnr.getLineNumber()+":"+line); } } catch (IOException e) { throw new RuntimeException("读取数据失败"); } finally { try { if(lnr!=null) lnr.close(); } catch (IOException e) { throw new RuntimeException("读取流关闭失败"); } } } }
四、装饰设计模式
1、目的
对已有对象进行功能增强。可定义类,将已有对象传入,基于已有对象的功能,并提供加强功能。自定义的该类称之为装饰类。
2、特点
装饰类通常都会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
3、装饰和继承的区别:
1)装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。
2)装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。
3)从继承结构转为组合结构。
注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。
示例:上面讲到的MyBufferedReader的例子就是最好的装饰设计模式的例子。
----------------------------------------------------------------------------------
第三讲 字节流
一、InputStream、OutputStream
1、字符流只能操作纯文本文件,字节流可以操作文本、多媒体等各种文件。
2、字节流对象可直接将数据写入到文件中,字符流操作数据要在字节和字符之间进行转换,字节流直接操作字节,所以不需要flush操作。
3、InputStream特有方法:int available();//返回文件中的字节个数
二、BufferedInputStream、BufferedOutputStream
1、目的: 提高读写效率。
2、特点:
read():会将字节byte型值提升为int型值
write():会将int型强转为byte型,即保留二进制数(&0xff)的最后八位。
三、自定义读取字节流缓冲区
需求:根据字节流缓冲区的原理,自定义一个字节流缓冲区。
注意:
1、字节流的读一个字节的read方法为什么返回值类型不是byte,而是int?
因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1;-1是读取结束的标志。数据还没有读完,返回-1。为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。而在写入数据时,只写该int类型数据的最低8位。byte类型的-1提升为int类型时还是-1。原因:因为在8个1前面补的全是1导致的,如果在8个1前面补0,即可以保留原字节数据不变,又可以避免-1的出现。将byte型数据&0xff即255即可。
import java.io.*; /** * DEMO:练习FileInputStream/FileOutputStream/BufferedInputStream/BufferedOutputStream * 功能:复制Mp3文件 * 自己实现MyBufferedInputStream: * 用byte[]数组缓存,用count记录缓存数量,用pos记录下标 **/ import java.io.*; class CopyMp3 { public static void main(String[] args) { // 用一个7M的mp3文件测试不同方法复制速度 // long start = System.currentTimeMillis(); // //测试FileInputStream、FileOutputStream复制 // singleByteCopy();//用时46312毫秒 // long end = System.currentTimeMillis(); // sop(end - start); // long start = System.currentTimeMillis(); // byteArrayCopy();//用时62毫秒 // long end = System.currentTimeMillis(); // sop(end - start); // long start = System.currentTimeMillis(); // buffCopy();//用时406毫秒 // long end = System.currentTimeMillis(); // sop(end - start); long start = System.currentTimeMillis(); testMyBufferedInputStream();//用时265毫秒 long end = System.currentTimeMillis(); sop(end - start); } public static void sop(Object o) { System.out.println(o); } // 一个个字节进行复制 public static void singleByteCopy() { FileInputStream fis = null; FileOutputStream fos = null; try { // 关联要复制的文件 fis = new FileInputStream("e:\\io\\d.mp3"); // 指定复制的路径 fos = new FileOutputStream("e:\\io\\dsingle.mp3"); int b = 0; while((b=fis.read())!=-1){ fos.write(b);; } } catch (IOException e) { throw new RuntimeException("复制失败"); } finally { try { if (fis != null) fis.close();// 关闭输入字节流 } catch (IOException e) { throw new RuntimeException("FileInputStream关闭失败"); } try { if (fos != null) fos.close();// 关闭输出字节流 } catch (IOException e) { throw new RuntimeException("FileOutputStream关闭失败"); } } } // 使用读数组方式进行复制 public static void byteArrayCopy() { FileInputStream fis = null; FileOutputStream fos = null; try { // 关联要复制的文件 fis = new FileInputStream("e:\\io\\d.mp3"); // 指定复制的路径 fos = new FileOutputStream("e:\\io\\darraycopy.mp3"); // 利用数组的读取方式 byte[] b = new byte[1024]; int len = 0; while ((len = fis.read(b)) != -1) { fos.write(b, 0, len); } } catch (IOException e) { throw new RuntimeException("复制失败"); } finally { try { if (fis != null) fis.close();// 关闭 } catch (IOException e) { throw new RuntimeException("FileInputStream关闭失败"); } try { if (fos != null) fos.close();// 关闭 } catch (IOException e) { throw new RuntimeException("FileOutputStream关闭失败"); } } } public static void buffCopy() { BufferedInputStream bfis = null; BufferedOutputStream bfos = null; try { bfis = new BufferedInputStream(new FileInputStream("e:\\io\\d.mp3")); bfos = new BufferedOutputStream(new FileOutputStream("e:\\io\\buffcopy.mp3")); int ch = 0; while ((ch = bfis.read()) != -1) { bfos.write(ch); } } catch (IOException e) { throw new RuntimeException("读取数据失败"); } finally { if (bfis != null) try { bfis.close(); } catch (IOException e) { throw new RuntimeException("bfis关闭失败"); } if (bfos != null) try { bfos.close(); } catch (IOException e) { throw new RuntimeException("bfos关闭失败"); } } } public static void testMyBufferedInputStream() { MyBufferedInputStream bfis = null; BufferedOutputStream bfos = null; try { bfis = new MyBufferedInputStream(new FileInputStream("E:\\IO\\d.mp3")); bfos = new BufferedOutputStream(new FileOutputStream("E:\\IO\\d_myBuff.mp3")); int ch = 0; System.out.println("first number:" + bfis.myRead()); while ((ch = bfis.myRead()) != -1) { bfos.write(ch); } } catch (IOException e) { throw new RuntimeException("读取数据失败"); } finally { if (bfis != null) try { bfis.myClose(); } catch (IOException e) { throw new RuntimeException("bfis关闭失败"); } if (bfos != null) try { bfos.close(); } catch (IOException e) { throw new RuntimeException("bfos关闭失败"); } } } } /** * 自定义模仿理解BufferedInputStream的原理 * 每次调用OS系统资源,将1024个字节数据存入数组 * */ class MyBufferedInputStream { private InputStream in; MyBufferedInputStream(InputStream in) { this.in = in; } int count = 0, pos = 0; byte[] b = new byte[1024];//字节缓冲区 public int myRead() throws IOException { if (count == 0) {//count记录缓冲区剩余字节数量 count = in.read(b);//读入字节到byte数组b,用count记录读入的字节数 pos = 0; if (count == -1) {//读入的byte时返回的是-1,标志着文件中数据已经全部读完 return -1; } byte by = b[pos];//每返回一个字节,缓冲区字节数目--,指针++ count--; pos++; return (by)&0xff; } else if (count > 0) {//缓冲区还有字节数据,依次取用 byte by = b[pos]; count--; pos++; return (by)&0xff;//byte类型提升为int类型,字节数增加,前三个字节被补1,原字节数据改变。 //通过与上0xff,将byte类型提升为int类型同时前三个字节补0,最后一个字节数据不变。 //在输出字节流写入数据时,只写该int类型数据的最低8位。 } return -1; } public void myClose() throws IOException { in.close(); } }
__________________________________________________________________
第四讲 流操作规律
一、键盘录入
1、System.in与out
System.in:标准输入设备,键盘。类型是InputStream.
Ssytem.out:标准的输出设备,控制台。类型是PrintStream是OutputStream的子类FilterOutputStream的子类。
2、整行录入
当使用System.in进行键盘录入时,只能一个字节一个字节录入。为了提高效率,可以自定义一个数组将一行字节进行存储。当一行录入完毕,再处理整行数据。这就是
BufferedReader类中readLine()的原理。
3、转换流
3.1 InputStreamReader将字节流通向字符流
a、获取键盘录入对象。
InputStream in=System.in;
b、将字节流对象转成字符流对象,使用转换流。
InputStreamReaderisr=new InputStreamReader(in);
c、为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReaderbr=new BufferedReader(isr);
//键盘录入最常见写法
BufferedReaderin=new BufferedReader(new InputStreamReader(System.in));
3.2 OutputStreamWriter字符流通向字节流
步骤和InputStreamReader转换流一样。
/* 需求:将键盘录入的数据,显示在控制台,当输入over时,表示结束 源:键盘录入。 目的:控制台。 */ import java.io.*; class Demo { public static void main(String[] args)throws IOException { //获取键盘录入对象。 //InputStream in=System.in; //将字节流对象转成字符流对象,使用转换流。 //InputStreamReader isr=new InputStreamReader(in); //为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader //BufferedReader br=new BufferedReader(isr); //键盘录入最常见写法 BufferedReader in=new BufferedReader(new InputStreamReader(System.in)); //字符流通向字节流 BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(System.out)); String s=null; while((s=in.readLine())!=null) { if("over".equals(s)) break; bw.write(s.toUpperCase());//写入数据 bw.newLine();//换行 bw.flush();//刷新 } bw.close();//关闭流资源 in.close(); } }
二、确定用哪种流对象
4.三步完成:
4.1 明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
4.2 操作的数据是否是纯文本。
是:字符流
否:字节流
4.3 当体系明确后,再明确要使用哪个具体的对象。通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
5、规律体现
5.1 将一个文本文件中数据存储到另一个文件中。复制文件。
1)源:因为是源,所以使用读取流:InputStream和Reader
明确体系:是否操作文本:是,Reader
明确设备:Reader体系中可以操作文件的对象是FileReader
是否需要提高效率:是,加入Reader体系中缓冲区 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
2)目的:输出流:OutputStream和Writer
明确体系:是否操作文本:是,Writer
明确设备:Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是,加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。
1)源:输入流,InputStream和Reader
是否是文本?否,InputStream
源设备:硬盘上的一个文件。InputSteam体系中可以操作文件的对象是FileInputSteam
是否需要提供效率:是,BufferedInputStream
BufferedInputSteambis=new BufferedInputStream(newFileInputStream("c:/users/asus/desktop/1.jpg"));
2)目的:输出流,OutputStream和Writer
是否是文本?否,OutputStream
源设备:硬盘上的文件,FileOutputStream
是否需要提高效率:是,加入BufferedOutputStream
BufferedOutputStreambos=newBufferedOutputStream(newFileOutputStream("c:/users/asus/desktop/2.jpg"));
5.2 需求:将键盘录入的数据保存到一个文件中。
1)源:InputStream和Reader
是不是纯文本?是,Reader
设备:键盘。对应的对象是System.in。——为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成
Reader。用Reader体系中转换流,InputStreamReader
InputStreamReaderisr = new InputStreamReader(System.in);
需要提高效率吗?需要,BufferedReader
BufferedReaderbufr = new BufferedReader(isr);
2)目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = newFileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
5.3 扩展:想要把录入的数据按照指定的编码表(UTF-8)(默认编码表是GBK),将数据存到文件中。
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘上的一个文件。使用 FileWriter。——但是FileWriter是使用的默认编码表:GBK。而存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。
该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流:FileOutputStream
OutputStreamWriter osw =new OutputStreamWriter(newFileOutputStream("d.txt"),"UTF-8");
需要高效吗?需要,BufferedWriter
BufferedWriter bufw = new BufferedWriter(osw);
记住:
转换流什么使用?
字符和字节之间的桥梁。通常,涉及到字符编码转换时,需要用到转换流。
练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
1)源:InputStream、Reader
是文本?是:Reader
设备:硬盘。上的文件:FileReader
是否需要提高效率?是:BufferedReader
BufferedReader br=new BufferedReader(newFileReader("1.txt"));
2)目的:OutputStream Writer
是文本?是:Writer
设备:控制台。对应对象System.out。由于System.out对应的是字节流,所以利用OutputSteamWriter转换流
是否提高效率?是:BufferedWriter
BufferedWriter bw =new BufferedWriter(newOutputStreamWriter(system.out));
/* 2、需求:想把键盘录入的数据存储到一个文件中。 源:键盘 目的:文件 把录入的数据按照指定的编码表(UTF-8),将数据存到文件中。 3、需求:想要将一个文件的数据打印在控制台上。 源:文件 目的:控制台 */ import java.io.*; class Demo { public static void main(String[] args)throws IOException { //键盘录入 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); //存入文件中,按照指定的编码表(UTF-8) BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("readin1.txt"),"UTF-8")); String line=null; while((line=br.readLine())!=null) { if("over".equals(line)) break; bw.write(line); bw.newLine(); bw.flush(); } /* //录入文件数据 BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("TransStreamDemo2.java"))); //显示在控制台 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); String line=null; while((line=br.readLine())!=null) { if("over".equals(line)) break; bw.write(line); bw.newLine(); bw.flush(); } */ } }
/** * 异常的日志信息 * 当程序在执行的时候,出现的问题是不希望直接打印给用户看的, * 是需要作为文件存储起来,方便程序员查看,并及时调整的。 * 可以创建一个PrintStream对象,传给System.setOut(),修改输出流设备 */ import java.io.*; import java.text.*; import java.util.*; class Demo { public static void main(String[] args) { try { int[] arr =new int[2]; System.out.println(arr[3]); } catch (Exception e) { try { Date d=new Date();//创建时间对象 //时间模块格式对象 SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); String s=sdf.format(d); PrintStream ps=new PrintStream("d:\\info.log");//打印流对象 System.setOut(ps);//修改输出流设备.通过System类的setIn,setOut方法可以对默认设备进行改变 ps.println(s);//输出时间 } catch (IOException ex) { throw new RuntimeException("文件创建失败"); } e.printStackTrace(System.out);//将异常信息输出指定输出流 } } }
//将系统属性信息保存到指定文本中 import java.util.*; import java.io.*; class Demo { public static void main(String[] args) { PrintStream ps = null; try { //获取系统信息: Properties pop = System.getProperties(); //创建输出流对象,将输出流中数据存入指定文件中 ps = new PrintStream("d:\\systeminfo.txt"); //将属性列表输出到指定的输出流 pop.list(ps); } catch (Exception e) { throw new RuntimeException("获取系统信息失败。"); } } }
---------------------------------------------------------------------
第一讲 File类
一、概述
1、File类:文件和目录路径名的抽象表现形式
2、特点:
1)用来将文件或目录封装成对象
2)方便于对文件与目录的属性信息进行操作
3)File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变
4)File对象可以作为参数传递给流的构造函数
二、File对象创建
方式一:
File f =new File("a.txt");
将a.txt封装成File对象。可以将已有的和未出现的文件或者文件夹封装成对象。
方式二:
File f2=newFile("c:\\abc","b.txt");
将文件所在目录路径和文件一起传入,指定文件路径。
方式三:
File d=new File("c:\\abc");
File f3=new File(d,"c.txt");
将文件目录路径封装成对象。再创建文件对象。降低了文件于父目录的关联性。
小知识:
File.separator表示目录分隔符,可以跨平台使用。相当于路径中的“\”(双斜杠\\在windows中表示表示转义后的分隔符,但是在linux系统中就不是)。
三、File类的常见方法
1、创建
boolean createNewFile();
//在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立就创建文件。而且文件已经存在,会覆盖。
boolean mkdir();//创建文件夹,只能创建一级文件夹
例:
File dir=new File("abc");
dir.mkdir();//创建abc这个文件夹
boolean mkdirs();//创建多级文件夹
2、删除
boolean delete();
//删除文件或目录。文件存在,返回true;文件不存在或者正在被执行,返回false。
void deleteOnExit();//在程序退出时删除指定文件
3、判断
boolean canExecute();//是否是可执行文件
boolean exists();//文件是否存在
boolean isFile();//是否是文件
boolean isDirectory();//是否是文件夹
boolean isHidden();//是否是隐藏文件
boolean isAbsolute();//文件是否是绝对路径
记住:在判断文件对象是否是文件或者目录时,必须要判断该文件对象封装的内容是否存在。通过exists判断。
4、获取信息
String getName();//获取文件名
String getPath();
//获取文件的相对路径(即创建的对象传入的参数是什么就获取到什么)
String getParent();
//获取文件父目录。返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。如果相对路径中有上一层目录,那么该目录就是返回结果。
String getAbsolutePath();//获取文件的绝对路径
long lastModified();//返回文件最后一次被修改的时间
long length();//返回文件长度
5、列出文件及文件过滤
static File[] listRoots();//列出可用的文件系统根目录,即系统盘符
String[] list();
//列出当前目录下所有文件,包括隐藏。调用list方法的file对象必须是封装了一个目录。该目录还必须存在。
String[] list(FilenameFilter filter);
//返回一个字符串数组,获取目录中满足指定过滤器的文件或目录。
//FilenameFilter:文件名过滤器,是一个接口,其中包含一个方法,accept(Filedir,String name),返回的是boolean型,对不符合条件的文件过滤掉。
File[] listFiles();//返回一个抽象路径名数组,获取当前文件夹下的所有文件和文件夹
File[] ListFiles(FilenameFilterfilter);//返回抽象路径名数组,获取目录中满足指定过滤器的文件或目录。
/* 练习:用String[] list(FilenameFilter filter)方法获取一个目录下所有的.java文件,其他文件不要。 思路:1、FilenameFilter是一个过滤器接口,用匿名内部类传入filter对象 2、复写FilenameFilter接口的accept(File file,String name)方法,并判断name是否是java文件 3、遍历String类型数组 */ import java.io.*; class GetJavaFile { public static void main(String[] args) { File file=new File("E:\\Java Study\\Practice\\day07"); getJavaFile(file); } //获取一个目录下所有的.java文件方法 public static void getJavaFile(File dir) { //传入FilenameFilter匿名内部类子类对象,并复写accept方法 String[] javaFile=dir.list(new FilenameFilter() { public boolean accept(File dir,String name) { return name.endsWith(".java");//判断文件名是否是以.java结尾 } }); System.out.println("len:"+javaFile.length); //遍历数组 for (String s : javaFile ) { System.out.println(s); } } }
四、递归
1、定义
当函数内每一次循环还可以调用本功能来实现,也就是函数自身调用自身。这种表现形式,或者编程手法,称为递归。
2、递归注意事项
a、限定条件。是来结束循环调用,否则是死循环。
b、注意递归的次数,尽量避免内存溢出。因为每次调用自身的时候都会先执行下一次调用自己的方法,所以会不断在栈内存中开辟新空间,次数过多,会导致内存溢出。
/* 需求:列出指定目录下文件或文件夹,包含子目录,即列出指定目录下所有内容(带层次的)。 分析,因为目录中还有目录,只有使用同一个列出目录功能的函数完成即可,在列出过程中出现的还是目录的话,还可以再调用本功能,这就是利用递归原理。 */ import java.io.*; class RecursionDemo { public static void main(String[] args) { //关联指定路径 File dir=new File("e:\\Java Study\\Practice"); //列出关联路径中所有的.java文件 allFileList(dir,0); } //列出指定目录下的所以内容 public static void allFileList(File dir,int level) { //有层次的输出 System.out.println(getLevel(level)+dir); level++; File[] fileArr=dir.listFiles();//获取本目录下的所以文件和目录的抽象路径 //遍历 for (File file : fileArr) { if(file.isDirectory()) { //如果目录下还是目录,则继续调用本函数 allFileList(file,level); } else System.out.println(getLevel(level)+file);//显示(列出)文件 } } //带层次的列表 public static String getLevel(int level) { StringBuilder sb=new StringBuilder(); sb.append("|--"); //每多一级目录,就多输出指定字符 for (int x=level;x>0 ; x--) { //sb.append("|--"); sb.insert(0,"| "); } return sb.toString(); } }
/* 删除一个带内容的目录。 删除原理: 在windows中,删除目录从里面往外面删除的。 既然是从里往外删除。就需要用到递归。 */ import java.io.*; class RemoveDir { public static void main(String[] args) { //指定目录 File dir=new File("e:\\1"); //删除目录 removeDir(dir); } //删除传入目录 public static void removeDir(File dir) { File[] files=dir.listFiles();//列出目录下的所以文件和文件夹 //遍历 for (File file : files ) { //如果还是目录且非隐藏 if(!file.isHidden()&&file.isDirectory()) removeDir(file);//继续删除目录里的内容 else System.out.println(file.toString()+":-file-:"+file.delete());//删除文件 } System.out.println(dir+":::dir:::"+dir.delete());//删除目录 } }
/* 练习: 将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。建立一个java文件列表的文件。 思路: 1、对指定的目录进行递归。 2、获取递归过程所有的java文件的路径。 3、将这些路径存储到集合中。 4、将集合中的数据写入到一个文件中。 */ import java.util.*; import java.io.*; class JavaFileList { public static void main(String[] args) { //指定目录 File dir=new File("e:/Java Study/Practice"); //定义一个List集合,用于存储.java文件的File对象 List<File> list =new ArrayList<File>(); //调用获取文件路径方法 fileToList(dir,list); //指定写入文件 File file=new File(dir,"javafilelist.txt"); //调用写入文件方法 writeToFile(list,file); } //获取指定文件夹内的所有java文件的绝对路径,并存入集合中 public static void fileToList(File dir,List<File> list) { File[] files=dir.listFiles();//列出dir路径下的所以文件和目录, //遍历 for (File file : files) { //如果是目录,则继续获取 if(file.isDirectory()) { list.add(file.getAbsoluteFile());//把父目录路径也存入 fileToList(file,list); } //将是.java文件的绝对路径存入 else if(file.getName().endsWith(".java")) list.add(file); } } //将集合中元素写入到一个文本文件中 public static void writeToFile(List<File> list,File file) { BufferedWriter bw=null; try { //使用字符流缓冲区对象关联写入的文件 bw=new BufferedWriter(new FileWriter(file)); for (File file0 : list ) { bw.write(file0.getAbsolutePath());//写入 bw.newLine();//换行 bw.flush();//刷新 } } catch (IOException e) { throw new RuntimeException("写入文件失败"); } finally { try { if(bw!=null) bw.close();//关流 } catch (IOException e) { throw new RuntimeException("流资源关闭失败"); } } } }
第二讲 Properties类
一、概述
1、Properties是Hashtable的子类,它具备Map集合的特点。而且它里面还有存储的键值对,都是字符串,无泛型定义。是集合中和IO技术相结合的集合容器。
2、特点:
1)可用于键值对形式的配置文件
2)在加载时,需要数据有固定的格式,常用的是:键=值
二、特有方法
1、设置
Object setProperty(String key,String value);
//设置键和值,调用Hashtable的方法put
2、获取
String getProperty(String key);
//指定key搜索value
Set<String> stringPropertyName();
//返回属性列表的键集,存入Set集合
3、加载流和存入流
void load(InputStream ism);
//从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void load(Reader reader);
//从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。
void list(PrintStream out);//将属性列表输出到指定的输出流
void store(OutputStreamout,String comments);
//对应load(InputStream )将属性列表(键值对)写入输出流。comments属性列表的描述。
void store(Writerwriter, String comments);
//对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。
示例
/* 练习:用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。 分析: 很容易想到的是:计数器。可是该计数器定义在程序中,随着该应用程序的退出,该计数器也在内存中消失了。 所以要建立一个配置文件,用于记录该软件的使用次数。该配置文件使用键值对的形式。键值对数据是map集合。数据是以文件形式存储。使用io技术。那么map+io——>Properties。 思路:1、用读取流关联文本信息文件。如果存在则读取,如果不存在,则创建 2、每次运行,将文件数据存入集合中,读取值,判断次数,如果小于等于5次,则次数增加1次,如果大于则输出提示信息。 3、将值小于等于5次的信息数据存入文件中 */ import java.util.*; import java.io.*; class RunCount { public static void main(String[] args)throws IOException { int count=runCount(); if(count>5)//如果程序被使用了超过5次,则终止使用,并提示 { System.out.println("次数到了,交钱!!!!!"); return ; } else System.out.println("程序第"+count+"次Run!"); } //获取程序运行的次数 public static int runCount()throws IOException { Properties ps=new Properties();//创建集合对象 File file=new File("info.ini");//将文件进行封装 if(!file.exists())//判断是否存在 file.createNewFile(); FileReader fr=new FileReader(file);//将文件于读取流进行关联 ps.load(fr);//加载流中的文件数据到集合中 int count=0;//定义计数器 String value=ps.getProperty("time");//获取次数值 if(value!=null)//如过值不等于null,则将其赋值给count { count=Integer.parseInt(value); } count++;//每启动一次自增 ps.setProperty("time",count+"");//将次数记录住集合 FileWriter fw=new FileWriter(file); ps.store(fw,"");//将集合中的数据存入硬盘文件中 fr.close();//关流 fw.close(); return count;//返回程序启动的次数 } }
第三讲 打印流
一、概述
1、打印流包括:PrintStream和PrintWriter
2、该流提供了打印方法,可将各种类型的数据都原样打印。
二、字节打印流:PrintStream
构造方法中可接收的参数类型:
1、File对象。File
2、字符串路径:String
3、字符输出流:OutputStream
三、字符串打印流:PrintWriter
构造方法中可接受的参数类型
1、File对象:File
2、字符串路径:String
3、字节输出流:OutputStream
4、字符输出流:Writer
示例
import java.io.*; class PrintStreamDemo { public static void main(String[] args) throws IOException { //键盘录入 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //打印流关联文件,自动刷新 PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true); String line = null; while((line=bufr.readLine())!=null) { if("over".equals(line))//结束字符 break; out.println(line.toUpperCase()); //out.flush(); } //关流 out.close(); bufr.close(); } }
第四讲 序列流
一、概述
1、SequenceInputStream对多个流进行合并。也被称为合并流。
2、常用构造函数
SequenceInputStream(Enumeration<?extends FileInputStream> e)
二、常见合并多个流文件步骤
1、创建集合,并将流对象添加进集合
2、创建Enumeration对象,将集合元素加入。
3、创建SequenceInputStream对象,合并流对象
4、创建写入流对象,FileOutputStream关联写入文件
5、利用SequenceInputStream对象和FileOutputStream对象读数据进行反复读写操作。
/* SequenceInputStream 合并流 需求:将三个文本文件中的数据合并到一个文本文件中 思路:1、创建一个Vector集合,将三个文本文件字节流添加到集合中 2、创建Enumeration对象,创建SequnceInputStream对象关联Enumeration 3、输出流关联新文本文件 4、反复读写操作 */ import java.util.*; import java.io.*; class SequenceInputStreamDemo { public static void main(String[] args)throws IOException { Vector<InputStream> ve=new Vector<InputStream>();//创建vector集合,并添加相关流对象 ve.add(new FileInputStream("1.txt")); ve.add(new FileInputStream("2.txt")); ve.add(new FileInputStream("3.txt")); Enumeration<InputStream> en=ve.elements();//创建枚举对象 SequenceInputStream sis=new SequenceInputStream(en);//合并流 FileOutputStream fos=new FileOutputStream("4.txt");//关联写入文件 //反复读写操作 byte[] buf=new byte[1024]; int len=0; while((len=sis.read(buf))!=-1) { fos.write(buf,0,len); } //关流 fos.close(); sis.close(); } }
/* 切割文件 需求:将一个mp3文件按1M大小切割成几部分 思路:1、使用文件字节流关联mp3文件 2、定义一个容器存储1M大小的数据,当存储满时,写入一个新文件中 */ import java.util.*; import java.io.*; class SplitFile { public static void main(String[] args) throws IOException { //指定要切割的文件 File file=new File("C:\\Users\\asus\\Desktop\\苏芮 - 一样的月光.mp3"); //将指定文件进行切割 splitFile(file); //指定要合并到的文件 File file1=new File("E:\\Java Study\\Practice\\day20\\splitFile\\一样的月光.mp3"); //将部分文件进行合并指定文件中 merge(file1); } //接收一个文件,将其按1M大小进行切割 public static void splitFile(File file)throws IOException { //关联要切割的文件 BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file)); BufferedOutputStream bos=null; //定义1M大小存储容器 byte[] buf=new byte[1024*1024]; int len=0,x=0; while ((len=bis.read(buf))!=-1) { //每满1M就写入一个新文件中 bos=new BufferedOutputStream(new FileOutputStream("E:\\Java Study\\Practice\\day20\\splitFile\\"+(++x)+".part")); bos.write(buf,0,len); bos.close();//没写完一个文件要记得关流 } //关流 bis.close(); } //将部分文件合并为一个可执行文件 public static void merge(File file)throws IOException { //定义一个集合存储这些部分文件关联路径数据 ArrayList<FileInputStream> al=new ArrayList<FileInputStream>(); for (int x=1;x<=6 ; x++) { al.add(new FileInputStream("E:\\Java Study\\Practice\\day20\\splitFile\\"+x+".part")); } //因为Enumeration是Vector特有的迭代方法,所以这里创建一个Enumeration类型的匿名内部类 final ListIterator<FileInputStream> it=al.listIterator(); Enumeration<FileInputStream> en=new Enumeration<FileInputStream>() { public boolean hasMoreElements() { return it.hasNext(); } public FileInputStream nextElement() { return it.next(); } }; //关联枚举对象 SequenceInputStream sis=new SequenceInputStream(en); //将合并的文件数据写入指定文件中 FileOutputStream fos=new FileOutputStream(file); //定义临时存储数据的数组 byte[] buf=new byte[1024]; int len=0; while((len=sis.read(buf))!=-1) { fos.write(buf,0,len);//写数据 } //关流 fos.close(); sis.close(); } }
第五讲 对象的序列化
目的:将一个具体的对象进行持久化,写入到硬盘上。
注意:静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。
如何将非静态的数据不进行序列化?
用transient 关键字修饰此变量即可。
Serializable:用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运算获取的。如果不需要自动获取一个uid,可以在类中手动指定一个名称为serialVersionUID id号。依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显式的UID的指定。
import java.io.*; class Person implements Serializable{ private static final long serialVersionUID = 42L; private transient String name;//用transient修饰后name将不会进行序列化 public int age; Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return name+"::"+age; } }
import java.io.*; class ObjectStream { public static void main(String[] args) throws Exception{ writeObj(); readObj(); } public static void readObj()throws Exception{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt")); Object obj = ois.readObject();//读取一个对象。 System.out.println(obj.toString()); } public static void writeObj()throws IOException{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt")); oos.writeObject(new Person("lisi",25)); //写入一个对象。 oos.close(); } }
第六讲 管道流
管道读取流和管道写入流可以像管道一样对接上,管道读取流可以读取管道写入流写入的数据。
注意:需要加入多线程技术,因为单线程,先执行read,会发生死锁,因为read方法是阻塞式的,没有数据的read方法会让线程等待。
import java.io.*; class Read implements Runnable { private PipedInputStream in; Read(PipedInputStream in) { this.in = in; } public void run() { try { byte[] buf = new byte[1024]; System.out.println("读取前。。没有数据阻塞"); int len = in.read(buf); System.out.println("读到数据。。阻塞结束"); String s= new String(buf,0,len); System.out.println(s); in.close(); } catch (IOException e) { throw new RuntimeException("管道读取流失败"); } } } class Write implements Runnable { private PipedOutputStream out; Write(PipedOutputStream out) { this.out = out; } public void run() { try { System.out.println("开始写入数据,等待6秒后。"); Thread.sleep(6000); out.write("一大波测试数据".getBytes()); out.close(); } catch (Exception e) { throw new RuntimeException("管道输出流失败"); } } } class PipedStreamDemo { public static void main(String[] args) throws IOException { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(); in.connect(out); Read r = new Read(in); Write w = new Write(out); new Thread(r).start(); new Thread(w).start(); } }
第七讲 RandomAccessFile
特点:
1:该对象即可读取,又可写入。
2:该对象中的定义了一个大型的byte数组,通过定义指针来操作这个数组。
3:可以通过该对象的getFilePointer()获取指针的位置,通过seek()方法设置指针的位置。
4:该对象操作的源和目的必须是文件。
5:其实该对象内部封装了字节读取流和字节写入流。
注意:实现随机访问,最好是数据有规律。
import java.io.*; class RandomAccessFileDemo{ public static void main(String[] args) throws IOException{ write(); // read(); // randomWrite(); } //随机写入数据,可以实现已有数据的修改。 public static void randomWrite()throws IOException{ RandomAccessFile raf = new RandomAccessFile("random.txt","rw"); raf.seek(8*4); System.out.println("pos :"+raf.getFilePointer()); raf.write("张三".getBytes()); raf.writeInt(102); raf.close(); } public static void read()throws IOException{ RandomAccessFile raf = new RandomAccessFile("random.txt","r");//只读模式。 //指定指针的位置。 raf.seek(8*1);//实现随机读取文件中的数据。注意:数据最好有规律。 System.out.println("pos1 :"+raf.getFilePointer()); byte[] buf = new byte[4]; raf.read(buf); String name = new String(buf); int age = raf.readInt(); System.out.println(name+"::"+age); System.out.println("pos2 :"+raf.getFilePointer()); raf.close(); } public static void write()throws IOException{ //rw:当这个文件不存在,会创建该文件。当文件已存在,不会创建。所以不会像输出流一样覆盖。 RandomAccessFile raf = new RandomAccessFile("random.txt","rw");//rw读写模式 //往文件中写入人的基本信息,姓名,年龄。 raf.write("张三".getBytes()); raf.writeInt(97); raf.close(); } }
第八讲 以流的读写思想来操作数组
ByteArrayInputStream:源:内存
ByteArrayOutputStream:目的:内存。
这两个流对象不涉及底层资源调用,操作的都是内存中数组,所以不需要关闭。
直接操作字节数组就可以了,为什么还要把数组封装到流对象中呢?
因为数组本身没有方法,只有一个length属性。为了便于数组的操作,将数组进行封装,对外提供方法操作数组中的元素。
/* 用流的读写思想来操作数据。 */ import java.io.*; class ByteArrayStream { public static void main(String[] args) { //数据源。在构造的时候,需要接收数据源。而且数据源是一个字节数组。 ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes()); //数据目的。在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。 ByteArrayOutputStream bos = new ByteArrayOutputStream(); int by = 0; while((by=bis.read())!=-1) { bos.write(by); } System.out.println(bos.size()); System.out.println(bos.toString()); // bos.writeTo(new FileOutputStream("a.txt")); } }
第七讲 Encoding
gbk编码,一个汉字占2个字节
utf-8编码,一个汉字占3个字节
联通这两个字符的特殊性
联通----用gbk编码的二进制四个字节数据为:
11000001
10101010
11001101
10101000
恰恰符合utf-8中 110 10 110 10打头的字符编码格式,notepad.exe在解码时会默认采用utf-8解码,导致解码出错。
import java.io.*; import java.util.*; class Demo{ public static void main(String[] args)throws IOException{ /* write(); write_utf8(); write_gbk();*/ // read(); byte[] b = "联通".getBytes(); for(int i=0; i<b.length; i++){ System.out.println(Integer.toBinaryString(b[i] & 0xff)); } } public static void write()throws IOException{ OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("moren.txt")); ow.write("你好"); ow.close(); } public static void write_utf8()throws IOException{ OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("utf-8.txt"),"utf-8"); ow.write("你好"); ow.close(); } public static void write_gbk()throws IOException{ OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk"); ow.write("你好"); ow.close(); } public static void read()throws IOException{ InputStreamReader in = new InputStreamReader(new FileInputStream("gbk.txt"),"utf-8"); char[] c = new char[10]; int len = in.read(c); String s = new String(c, 0, len); in.close(); System.out.println(s); } }
发表评论
-
Reflect
2015-05-13 00:34 389第一讲 反射的应用 ... -
Regular Expression
2015-05-06 15:50 431正则表达式 一、概述 1、 概念:符合一定规则 ... -
网络编程
2015-05-04 12:07 443第一讲 概述 1、网络模型:OSI参考模型和TCP/ ... -
System、Runtime、Date、DateFormat、Calendar、Math、Random
2015-03-15 00:55 470第一讲 System类 一、概述 1、System是描 ... -
多线程
2015-03-14 22:23 373一、多线程概述 ... -
Generic 泛型
2015-03-13 23:23 523第一讲 泛型(Gene ...
相关推荐
Java IO应届生培训讲义是一份面向刚毕业的大学生进行Java IO相关知识的培训资料,它涵盖了Java IO的基础知识、不同的IO模型以及Java中的BIO、NIO和AIO高级IO类库。下面详细解释这些知识点: 1. 用户空间和内核空间 ...
Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的重要部分,涉及文件、网络、内存等数据传输。本文将深入探讨Java IO的基本概念、分类、选择流的策略以及常用的流类型。 首先,File类是Java IO的...
java IO教程,java IO教程,java IO教程,java IO教程java IO教程java IO教程java IO教程java IO教程,java IO教程java IO教程java IO教程java IO教程java IO教程,java IO教程,java IO教程,java IO教程,java IO...
Java IO(Input/Output)是Java编程语言中用于处理输入和输出操作的重要组成部分。它提供了一整套类库,使得开发者能够有效地读取和写入数据到不同的源和目标,如文件、网络、内存缓冲区等。Java IO体系结构设计得...
Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的基础框架,它提供了丰富的类库,使得程序能够与各种设备、文件、网络进行数据交互。然而,传统的IO模型在处理大量并发连接时表现出效率较低的问题,...
《Java IO.chm》是一个关于Java输入/输出(IO)技术的压缩文件,其中包含了丰富的资料,适合开发者深入理解和学习Java IO系统。这篇详细的总结将围绕Java IO体系结构、核心类、流的概念、缓冲区、转换流、字符集、...
Java IO 详解 Java IO(Input/Output)是 Java 语言中用于处理输入输出操作的类库,提供了大量的类和方法来实现文件、网络、字节流等方面的输入输出操作。下面对 Java IO 中的重要知识点进行详细说明。 一、File ...
Java IO处理类是Java平台中用于输入输出操作的核心部分,它允许程序与各种类型的输入源(如文件、网络连接)以及输出目标(如显示器、打印机)进行交互。本篇文章将全面解析Java IO处理类,包括基本概念、常用类库、...
Java IO编程是Java平台中处理输入输出操作的重要组成部分,它提供了丰富的类库,使得开发者能够高效地进行数据的读取、写入、流的管理和转换。在这个集合中,我们主要探讨的是Java IO在文件读写方面的实践应用。 一...
Java IO流技术是Java平台中用于处理输入输出的重要机制,其核心在于数据的传输,从数据源到程序或从程序到目的地。在Java中,流分为两大类:输入流(InputStream、Reader)和输出流(OutputStream、Writer)。输入流...
在“JavaIODemo”这个示例中,可能会包含以上提到的一些或全部Java IO操作的代码实例,通过这些实例,我们可以学习如何在实际项目中应用Java IO API。实践是掌握Java IO的最佳方式,通过对这些示例的分析和运行,...
Java IO(Input/Output)是Java编程语言中用于处理输入和输出操作的重要组成部分。它提供了丰富的类库,允许程序员在程序之间传输数据,包括从文件、网络、内存缓冲区到其他程序或系统组件。Java IO API是Java平台的...
JavaIO流详解归纳 Java 的核心库 java.io 提供了全面的 IO 接口,包括文件读写、标准设备输出等。Java 中 IO 是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入。在项目开发中,IO 是非常...
Java IO操作是Java编程中的重要组成部分,主要用于处理输入和输出数据。在Java中,IO操作涉及到文件、字节流、字符流以及管道流等多个概念。下面将详细解释这些知识点。 首先,我们来看“文件类”。在Java中,`java...
Java IO 与 装饰模式 在Java编程中,输入输出(IO)处理是程序设计中的重要组成部分,用于读取、写入和处理数据。Java IO库提供了一整套类来支持各种类型的输入输出操作,包括文件、网络、内存等。而装饰模式是一种...
2、常用21个IO流:FileWriter、FileReader、...3、JAVA IO流经典代码示例,示例从易到难。代码功能涉及字节、字符、字符串、文本文件、图片、音频、视频。演示错误用法和经典用法。 4、代码的结构可查看README文件。
Java IO流是Java平台中的重要组成部分,用于处理输入和输出操作。它允许程序与外部设备如硬盘、网络、内存等进行数据传输。IO流的概念基于流(Stream)模型,数据以字节或字符序列的形式流动。Java IO库提供了丰富的...
Java IO流是Java编程语言中处理输入输出操作的重要部分,尤其在数据传输、文件读写等方面发挥着核心作用。本文将深入探讨Java IO流的基本概念、类型以及它们在实际开发中的应用。 首先,理解IO流的基本概念至关重要...
Java IO(Input/Output)是Java平台中处理输入与输出数据的核心部分,它提供了丰富的类库,使得开发者能够高效地进行文件、网络、内存以及其他I/O流的操作。本篇文章将全面解析Java IO工具类,帮助你理解并掌握其在...