------<ahref="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
前言
在本章中,我想尝试用一种新的方法来学习知识。传统的方式下,我们按部就班的抄写老师的笔记,加上自己个人的注解和理解,随后把知识体系完完整整,十分详尽的罗列出来。然后再通过不断的复习和巩固,做一些习题来达到更深层次的理解。这种方式固然有它的好处,但是也许并不是能够最快单刀直入问题核心的方式。对于程序员这个工作来说,要学习的东西实在是浩如烟海,如果每一次都用最传统的方式来学习,恐怕在效率上值得探讨。对于以前的那种学习方式,我姑且称之为“自底向上”的学习,这种方式对基础知识的掌握当然十分牢固,但是它有一个缺陷,便是你可能会迷失在庞大的基础森林之中,很难一眼看穿其实际的用途。
现在,我思考了一种“自顶向下”的学习方法,先从这个知识章节所能解决的问题入手,层层深入,最终剥离出最本质和核心的内容。同时,由于在一开始便看到了实际的应用过程,对知识的体系会有更深刻的认识和体会,因为解决实际问题的过程往往是一种综合应用基础知识的过程。自顶向下当然不是什么新名词,不过不管别人是否曾把这种方法应用在什么方面上,至少对我来说,是独立思考出这样的方式,并且十分乐意做一些初步的实验。
IO知识能解决哪些实际问题?
在研究这个问题之前,首先应该先对IO的体系有一个大致的了解,不管是否真正理解其中的名词,如果能够看到问题的边界在哪里,对于深入理解问题本身是很有好处的。其实在写第一篇JAVA博客的时候,我就已经对整个JAVA框架做了整理,这种高空的视角确实是我所乐衷的。接下来,我就对IO流的知识进而一个简单的分类,并且把实际解决的问题归入到相应的分类中。
字符流
在硬盘上创建文件并写入数据(存)
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException//如果瞎传路径,无法继续进行文件操作
{
//创建一个FileWriter对象。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是在明确数据要存放的目的地:D:\Java\workspaceLite\Try
FileWriter fw = new FileWriter("demo.txt");//该对象一被初始化就必须要明确被操作的文件
//调用write方法,将字符串写入到流中。
fw.write("abcde");
//刷新流对象中的缓冲中的数据,将数据刷到目的地中。
fw.flush();//如果不flush,将没有数据写入到demo.txt文件中,还在缓存里
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据,并将数据刷到目的地中。
fw.close();//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
}
}
对硬盘上已有的文件进行续写(存)
import java.io.*;
class FileWriterDemo2
{
public static void main(String[] args) throws IOException
{
//传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。
FileWriter fw = new FileWriter("demo.txt",true);//想要在demo.txt文件上续写,就需要在该文件初始化时,传递true
fw.write("nihao\r\nxiexie");//windows的回车符\r\n
fw.close();
}
}
读取硬盘上已有的文件(打印到控制台)
read方式
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReader fr = new FileReader("demo.txt");
//调用读取流对象的read方法。
int ch = 0;
while((ch=fr.read())!=-1)//read():一次读一个字符。而且会自动往下读,如果到达末尾会返回-1
{
System.out.println("ch=" + ch);
//System.out.println("ch=" + (char)ch); //进行(char)强转后可以输出字符
}
/* demo.txt文件内现有的内容:abcde, 打印结果如下:
ch=97
ch=98
ch=99
ch=100
ch=101*/
/*另一种写法:
while(true)
{
int ch = fr.read();
if(ch==-1)
break;
System.out.println("ch="+(char)ch);
}
*/
fr.close();
}
}
字符数组方式
import java.io.*;
class FileReaderDemo2
{
public static void main(String[] args) throws IOException
{
//开读取流
FileReader fr = new FileReader("demo.txt");
//定义一个字符数组。用于存储读到的字符。
char[] buf = new char[1024];//2Kb(一个字符是两个字节)
int num = 0;
while((num=fr.read(buf))!=-1)//int read(char[] cbuf) ,该read(char[])返回的num是读到字符个数。
{
System.out.println(new String(buf,0,num));//将字符数组变为字符串后进行打印
//String(字符数组名, 开始取的位置, 取几个)
//new String(buf,0,num)就是说读到几个打几个,否则最后一次读的时候可能只读到1个,但是会把字符数组中内容全部打印出来
}
//关读取流
fr.close();
}
}
//输出结果:abcde
磁盘复制文本文件到磁盘(取和存)
import java.io.*;
class CopyTest//CopyTest写成了CopyText,与创建的时候类名不同,程序不会报错,但是也不会正确运行
{
public static void main(String[] args) throws IOException
{
copy_1();
}
//方式1:读一个字符,写一个字符(效率较低)
public static void copy_1()throws IOException
{
//创建目的地
FileWriter fw = new FileWriter("Demo2.txt");//目的
//与已有文件关联
FileReader fr = new FileReader("SingleDemo.java");//来源
//添加绝对路径的方法:new FileReader("D:/Java/workspaceLite/Try/SingleDemo.java")
//如果SingleDemo.java文件没有放在D:\Java\workspaceLite\Try中,会报FileNotFoundException
int ch = 0;//初始化
while((ch=fr.read())!=-1)//读一个
{
fw.write(ch);//写一个(写到流里面了)
}
fw.close();//关闭FileWriter
fr.close();//关闭FileReader
}
//方式2:使用字符数组,一次性读一次性写(数据保存在内存中,效率较高)
public static void copy_2()
{
//初始化FileWriter和FileReader
FileWriter fw = null;
FileReader fr = null;
//try...catch...finally处理
try
{
fw = new FileWriter("Demo3.txt");
fr = new FileReader("SingleDemo.java");
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1)
{
fw.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
if(fr!=null)
try
{
fr.close();//close是总是要执行的,所以放在finally中
}
catch (IOException e)
{
}
if(fw!=null)
try
{
fw.close();
}
catch (IOException e)
{
}
}
}
}
使用缓冲区技术在磁盘写入小说章节(存)
假设有一个小说家想要在txt文件中生成第1~20章标题,如:第1章、第2章
import java.io.*;
class BufferedWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个字符写入流对象。
FileWriter fw = new FileWriter("章节.txt");
//将需要被提高效率的流对象作为参数传递给缓冲区的构造函数
BufferedWriter bufw = new BufferedWriter(fw);//为了提高字符写入流效率。加入了缓冲技术。
//缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。
//进行的写入操作
for(int x = 1; x <= 20; x++)
{
bufw.write("第"+ x + "章:");
bufw.newLine();//该缓冲区中提供了一个跨平台的换行符。newLine();
bufw.flush();
}
//bufw.flush(); //只要用到缓冲区,就要记得刷新。
bufw.close();//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
}
}
使用缓冲区技术读取静夜思文档(取)
import java.io.*;
class BufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个读取流对象和文件相关联。
FileReader fr = new FileReader("静夜思.txt");
//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line=bufr.readLine())!=null)//readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
//一次读一行的方法 readLine,方便于对文本数据的获取,当返回null时,表示读到文件末尾。
{
System.out.print(line);//输出:《静夜思》李白:床前明月光,疑是地上霜。举头望明月,低头思故乡。
}
bufr.close();
}
}
/*如果使用println方法,则程序输出:
《静夜思》
李白:
床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。
*
*/
使用缓冲区技术复制一个.java文件(取和存)
核心代码部分bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
String line = null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
字节流
使用字节流来操作文件
import java.io.*;
class FileStream
{
public static void main(String[] args) throws IOException
{
readFile_3();
}
//字节流读取方式之一个个读
public static void readFile_1()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
int ch = 0;
while((ch=fis.read())!=-1)
{
System.out.println((char)ch);
}
fis.close();
}
//字节流读取方式之用字符数组读
public static void readFile_2()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1)
{
System.out.println(new String(buf,0,len));
}
fis.close();
}
//字节流读取方式之使用FileInputStream.available()方法
public static void readFile_3()throws IOException
{
FileInputStream fis = new FileInputStream("fos.txt");
//int num = fis.available();Returns an estimate of the number of remaining bytes that can be read
byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。不用再循环了。
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
//字节流写入方式
public static void writeFile()throws IOException
{
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("abcde".getBytes());//以字节流的方式在文件中写入abcde
fos.close();
}
}
在磁盘上复制图片
import java.io.*;
class CopyPic
{
public static void main(String[] args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("c:\\2.bmp");//字节流读取对象和图片文件关联
fis = new FileInputStream("c:\\1.bmp");
byte[] buf = new byte[1024];//字节数组方式
int len = 0;
while((len=fis.read(buf))!=-1)//读取
{
fos.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("复制文件失败");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
使用带缓冲功能的字节流复制图片
public class BufCopyPic {
public static void main(String[] args) {
BufferedInputStream bufis = null;//如果不在这里先建立bufis和bufos的引用,那么在finally代码块中的bufis将会无法访问到try中的bufis
BufferedOutputStream bufos = null;//在try外建立引用,在try内进行初始化
try
{
bufis = new BufferedInputStream(new FileInputStream(
"d:\\heimawoo.jpg"));//在D盘有一个名为heimawoo,格式为jpg的文件
bufos = new BufferedOutputStream(new FileOutputStream(
"e:\\heimawoo.jpg"));//将该文件复制到E盘中
int byt = 0;
while ((byt = bufis.read()) != -1){//BufferedInputStream读一个
bufos.write(byt);//BufferedOutputStream写一个
}
}
catch (IOException e)
{
throw new RuntimeException("图片拷贝异常");
}
//关闭流的动作一定要执行到,所以要放在finally中
finally {
try {
if (bufis != null)//初始化如果抛出异常,对象不存在,bufis为空,如果此时直接调用close,会出错
bufis.close();//关闭BufferedInputStream
} catch (IOException e) {//bufis.close()本身也需要进行异常处理
throw new RuntimeException("读取流关闭异常");
}
try {
if (bufos != null)
bufos.close();//关闭BufferedOutputStream
} catch (IOException e) {bufos.close()本身也需要进行异常处理
throw new RuntimeException("写入流关闭异常");
}
}
}
}
转换流
键盘录入一行数据并打印其大写(取)
import java.io.*;
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
//获取键盘录入对象。
//InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流。InputStreamReader:这样就可以使用字符流的readLine方法
//InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
//BufferedReader bufr = new BufferedReader(isr);
//键盘的最常见写法(简化书写格式)
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
将键盘录入的数据保存到一个文件中
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("demo4.txt")));
将一个文本数据打印在控制台上
//键盘的最常见写法(简化书写格式)
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("SingleDemo.java")));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
File类
接收文件名返回扩展名
public class Test {
public static void main(String[] args) {
File file = new File("d:\\测试文件.doc");//new一个File类
getExName(file);//调用该获取文件扩展名方法
}
//创建一个getExName(获取文件扩展名)的方法
public static void getExName(File file){
String fileName = file.getName();//利用File类的getName方法获取到文件名,存入fileName的字符串变量中
String exName = fileName.substring(fileName.lastIndexOf(".") + 1);//用fileName截取其子串,在'.'号的后一位开始取
//因为substring(int beginIndex)这个构造函数,传入的是截取开始的位置,包含头不包含尾
System.out.println("文件:" + fileName + "的扩展名是" + exName);//输出:文件:测试文件.doc的扩展名是doc
}
}
获取d盘目录下后缀名为".java"的文件
import java.io.File;
import java.io.FilenameFilter;
public class FileListDemo {
public static void main(String[] args){
listDemo();
}
public static void listDemo(){
File dir = new File("d:\\");
String[] names = dir.list(new SuffixFilter(".java"));
for(String name: names){
System.out.println(name);
}
}
}
class SuffixFilter implements FilenameFilter{
private String suffix;
public SuffixFilter(String suffix){
super();
this.suffix = suffix;
}
public boolean accept(File dir, String name){
return name.endsWith(suffix);
}
}
获取c盘目录下的隐藏文件
import java.io.File;
import java.io.FilenameFilter;
public class FileListDemo2 {
public static void main(String[] args){
listDemo();
}
public static void listDemo(){
File dir = new File("c:\\");
File[] files = dir.listFiles(new FilterByHidden());
for(File file: files){
System.out.println(file);
}
}
}
class FilterByHidden implements FilenameFilter{
public boolean accept(File dir, String name){
return dir.isHidden();
}
}
建立一个java文件列表文件
import java.io.*;
import java.util.*;
class JavaFileList
{
public static void main(String[] args) throws IOException
{
File dir = new File("d:\\java1223");
List<File> list = new ArrayList<File>();
fileToList(dir,list);
//System.out.println(list.size());
File file = new File(dir,"javalist.txt");
writeToFile(list,file.toString());
}
public static void fileToList(File dir,List<File> list)
{
File[] files = dir.listFiles();
for(File file : files)
{
if(file.isDirectory())
fileToList(file,list);
else
{
if(file.getName().endsWith(".java"))
list.add(file);
}
}
}
public static void writeToFile(List<File> list,String javaListFile)throws IOException
{
BufferedWriter bufw = null;
try
{
bufw = new BufferedWriter(new FileWriter(javaListFile));
for(File f : list)
{
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw e;
}
finally
{
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
throw e;
}
}
}
}
Properties
限制程序运行次数
/*
* 获取一个应用程序运行的次数,如果超过5次,给出使用次数已到请注册的提示,并不要再运行程序。
* 分析:程序启动时,应该先读取这个用于记录计数器信息的配置文件。
* 获取上一次计数器次数。并进行使用次数的判断。
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class Test1 {
public static void main(String[] args) throws IOException{
getAppCount();
}
public static void getAppCount() throws IOException{
//将配置文件封装成File对象
File confile = new File("count.properties");
if(!confile.exists())
confile.createNewFile();
FileInputStream fis = new FileInputStream(confile);
Properties prop = new Properties();
prop.load(fis);
//从集合中通过键获取次数
String value = prop.getProperty("time");
//定义计数器,记录获取到的次数
int count = 0;
if(value != null){
count = Integer.parseInt(value);
if(count >= 5){
throw new RuntimeException("The times are used up. Pls register!");
}
}
count++;
//将改变后的次数重新存储到集合中
prop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(confile);
prop.store(fos, "");
fos.close();
fis.close();
}
}
IO知识的系统总结
在之前的诸多实例程序的学习过程中,我逐步了解了许多相关的知识点,并且直接就能够看到它们的实际应用,接下来,就需要在感性认识的基础上,升华到理性认识,结合老师的笔记,对这部分的知识进行一个比较系统的总结。
字节流、字符流、转换流:流操作的基本规律
流操作的基本规律:
1,明确源和目的。源:输入流。InputStream Reader目的:输出流。OutputStream Writer。2,操作的数据是否是纯文本。是:字符流。不是:字节流。3,当体系明确后,在明确要使用哪个具体的对象。通过设备来进行区分:源设备:内存,硬盘。键盘目的设备:内存,硬盘,控制台。
File类操作归纳
File类常见方法:
1,创建boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。boolean mkdir():创建文件夹。boolean mkdirs():创建多级文件夹。2,删除boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。void deleteOnExit();在程序退出时删除指定文件。3,判断boolean exists() :文件是否存在.isFile():isDirectory();isHidden();isAbsolute();4,获取getName():getPath():getParent():getAbsolutePath()long lastModified()long length()
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args){
constructorDemo();
try {
FileMethodDemo();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void constructorDemo(){
//可以将一个已存在的或不存在的文件或目录封装成file对象
File f1 = new File("a.txt");
File f2 = new File("d:\\a.txt");
File f = new File("d:\\a.txt");
File f3 = new File(f,"a.txt");
File f4 = new File("d:"+File.separator+"a.txt");
}
public static void FileMethodDemo() throws IOException{
File file1 = new File("file.txt");
File file2 = new File("d:\\file.txt");
//获取
System.out.println("name:"+file2.getName());
System.out.println("path1:"+file1.getPath());
System.out.println("absPath:"+file1.getAbsolutePath());
System.out.println("len:"+file2.length());
System.out.println("parent1:"+file1.getParent());
System.out.println("parent2:"+file2.getParent());
long time = file2.lastModified();
Date date = new Date(time);
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String str_time = df.format(date);
System.out.println("str_time:"+str_time);
//创建和删除
boolean b1 = file1.createNewFile();
System.out.println("b1 = "+b1);
boolean b2 = file1.delete();
System.out.println("b2 = "+b2);
File dir = new File("ab/cd/ef");
boolean b3 = dir.mkdir(); //创建多级目录
System.out.println("b3 = "+b3);
boolean b4 = dir.delete(); //删除最里层目录
System.out.println("b4 = "+b4);
//判断
if(!file1.exists())
file1.createNewFile();
if(file1.exists()){
System.out.println(file1.isFile());
System.out.println(file1.isDirectory());
}
dir.mkdirs();
if(dir.exists()){
System.out.println(dir.isFile());
System.out.println(dir.isDirectory());
}
//重命名
file1.renameTo(file2);
System.out.println(file1.getName());
//系统根目录和容量获取
File[] files = File.listRoots();
for (File file: files){
System.out.println(file);
}
File file = new File("User/");
System.out.println(file.getFreeSpace());
System.out.println(file.getTotalSpace());
System.out.println(file.getUsableSpace());
}
}