您的位置:首页 > 编程语言 > Java开发

Java基础-- IO

2015-07-24 18:22 603 查看

第一讲:IO概述

一、概念

通过不同输入输出设备之间的数据传输,称为“流“,JAVA中的流位于java.io包中,称为IO流,即Input Output的缩写。

二、特点:

1)IO流用来处理设备间的数据传输。

2)Java对数据的操作是通过流的方式。

3)Java用于操作流的对象都在IO包中。

4)流按操作数据分为两种:字节流和字符流。

5)流按流向分为:输入流和输出流。

注意:流只能操作数据,而不能操作文件。

三、IO流的常用基类:

1)字节流的抽象基流:InputStream和OutputStream。

2)字符流的抽象基流:Reader和Writer。
第二讲:字节流

一、概述

字节流用于操作字节输入输出的流,分为字节输入流和字节输出流。

二、字节流体系

OutputStream:输出字节流的所有类的超类。

|--->FileOutputStream:文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。

|--->BufferedOutputStream:字节写入流缓冲区

|--->PrintStream:打印流

InputStream:字节输入流的所有类的超类。

|--->FileInputStream:文件字节读取流

|--->BufferedInputStream:字节读取流缓冲区

三、常用方法

读:

int available() ;返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

int read();从输入流中读取数据的下一个字节。

int read(byte[] b, int off, int len); 将输入流中最多 len 个数据字节读入 byte 数组。

void close() ;关闭此输入流并释放与该流关联的所有系统资源。

写:

void flush() ;刷新此输出流并强制写出所有缓冲的输出字节。

void write(byte[] b, int off, int
len);将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

程序示例:

/*方法一:自定义缓冲区完成文件的读写操作。
* 需求:文件的拷贝
* 思路:先通过输入流读出文件中的内容,在通过输出流将数据写入文件中。
*/
public static void main(String[] args) throws IOException {
//创建一个字节输入流
FileInputStream fis=new FileInputStream("D:\\qiao.txt");
//创建一个字节输出流
FileOutputStream fos=new FileOutputStream("D://aa.txt");
int len=0;//记录每次读到的字节
byte[] b=new byte[1024];//自定义一个字节缓冲区
while((len=fis.read(b))!=-1){//判断是否读到文件尾
fos.write(b, 0, len);//将读出到的文件内容写到fos中
}
fis.close();//关闭流
fos.close();
}
}


/*
* 方法二:带缓冲的字节流完成文件的读写操作。
* 需求:读取文件夹中的数据,将其打印在控制台上。
*/
public static void main(String[] args) throws IOException {
//创建一个带缓冲区的输入流
BufferedInputStream bfis=new BufferedInputStream(new FileInputStream("D://qiao.txt"));
//创建一个带缓冲区的输出流
BufferedOutputStream bfos=new BufferedOutputStream(System.out);
int len=0;
while((len=bfis.read())!=-1){ //判读是否读到文件尾
bfos.write(len);  //将读取的数据写入到文件中
}
bfis.close();//关闭流
bfos.close();
}
}
第三讲:字符流

一、简述

1、字符流中的对象融合了编码表。使用的是默认的编码,即当前系统的编码。

2、字符流只用于处理文字数据,而字节流可以处理媒体数据。

二、字符流体系

Reader:用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。

|---BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

|---LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。

|---InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

|---FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。

Writer:写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。

|---BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

|---OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

|---FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。

|---PrintWriter:向文本输出流打印对象的格式化表示形式。

三、字符流的读写

1、写入字符流步骤

a、创建一个FileWriter对象,该对象一被初始化,就必须要明确被操作的文件。且该目录下如果已有同名文件,则同名文件将被覆盖。其实该步就是在明确数据要存放的目的地。

b、调用write(String s)方法,将字符串写入到流中。

c、调用flush()方法,刷新该流的缓冲,将数据刷新到目的地中。

d、调用close()方法,关闭流资源。但是关闭前会刷新一次内部的缓冲数据,并将数据刷新到目的地中。

close()和flush()区别:

flush()刷新后,流可以继续使用;

而close()刷新后,将会关闭流,不可再写入字符流。

注意:

1、其实java自身不能写入数据,而是调用系统内部方式完成数据的书写,使用系统资源后,一定要关闭资源。

2、文件的数据的续写是通过构造函数 FileWriter(Strings,boolean append),在创建对象时,传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。(windows系统中的文件内换行用\r\n两个转义字符表示,在linux系统中只用\n表示换行)

3、由于在创建对象时,需要指定创建文件位置,如果指定的位置不存在,就会发生IOException异常,所以在整个步骤中,需要对IO异常进行try处理。

程序示例:

/*
* 带缓冲的字符流完成文件的读写操作。
* 需求:读取文件夹中的数据,将其打印在控制台上。
*/
public static void main(String[] args) throws IOException {
BufferedReader br=null;
BufferedWriter bw=null;
try{
//创建一个字符输入流缓冲区,关联文件
br=new BufferedReader(new FileReader("D:\\qiao.txt"));
//创建一个字符输出流缓冲区,关联控制台
bw=new BufferedWriter(new OutputStreamWriter(System.out));
String len=null;
while((len=br.readLine())!=null){//判断是否读到文件尾
bw.write(len); //将读到的文件数据写入到文件中
bw.flush();   //刷新流
bw.newLine();	//换行
}
}catch(IOException e){
throw new RuntimeException("读写出错!");
}finally{
try{
if(br!=null){
br.close();//关闭流
}
}catch(IOException e){
throw new RuntimeException("输入流关闭出错!");
}
}
try{
if(bw!=null){
bw.close();//关闭流
}
}catch(IOException e){
throw new RuntimeException("输出流关闭出错!");
}
}
}


注意:想要操作文本文件,必须要进行编码转换,而编码转换动作转换流都完成了。所以操作文件的流对象只要继承自转换流就可以读取一个字符了。

四、LineNumberReader

在BufferedReader中有个直接的子类LineNumberReader,其中有特有的方法获取和设置行号:

setLineNumber();设置初始行号。

getLineNumber();获取行号。
程序示例:

BufferedReader br=new BufferedReader(new FileReader("D://qiao.txt"));//创建字符输入流
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));//创建字符输出流
LineNumberReader lr=new LineNumberReader(br);//包装
lr.setLineNumber(0);//设置读出文件的起始行号
String len=null;
while((len=lr.readLine())!=null){
bw.write(lr.getLineNumber()+": "+len);//将行号写入到文件中
bw.flush();
bw.newLine();
}
lr.close();//关流
bw.close();
}
}
程序运行结果:



第四讲:打印流

一、概述

1、打印流包括:PrintStream和PrintWriter

2、该流提供了打印方法,可将各种类型的数据都原样打印。

二、字节打印流:PrintStream

构造方法中可接收的参数类型:

1、File对象。File

2、字符串路径:String

3、字符输出流:OutputStream

三、字符串打印流:PrintWriter

构造方法中可接受的参数类型

1、File对象:File

2、字符串路径:String

3、字节输出流:OutputStream

4、字符输出流:Writer
程序示例:

<span style="font-size:14px;">BufferedReader bis=new BufferedReader(new InputStreamReader(System.in ));//创建字节输入流
PrintWriter pw=new PrintWriter(System.out ,true);//打印流关联文件,自动刷新
String len=null;
while((len=bis.readLine())!=null){
if("end".equals(len))//输入字符串为"end"时,退出
break;
System.out.println(len);//打印到控制台
}
bis.close();
pw.close();
}
}  </span>


四、IO流操作规律

1.明确源和目的。

数据源:就是需要读取,可以使用两个体系:InputStream、Reader;

数据汇:就是需要写入,可以使用两个体系:OutputStream、Writer;

2.操作的数据是否是纯文本数据?

如果是:数据源:Reader;数据汇:Writer

如果不是:数据源:InputStream;数据汇:OutputStream

3.明确操作的数据设备。

数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)

数据汇对应的设备:硬盘(File),内存(数组),控制台(System.out)。

4.需要在基本操作上附加其他功能吗?比如缓冲。

如果需要就进行装饰。

第五讲:File类

一、概述

1.File类:将文件系统中的文件和文件夹封装成了对象。提供了更多的属性和行为可以对这些文件和文件夹进行操作。这些是流对象办不到的,因为流只操作数据。

2.特点:

1)用来将文件或文件夹封装成对象。

2)方便于对文件与文件夹的属性信息进行操作。

3)File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变。

4)File对象可以作为参数传递给流的构造函数。

三、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);返回抽象路径名数组,获取目录中满足指定过滤器的文件或目录。
程序示例:

/*
* 编写程序,将指定目录下所有的.java文件拷贝到另一个目的中,将扩展名改为.txt。
*  定义一个函数,函数功能是遍历当前目录所有非文件夹的文件
*  把后缀是.java文件的文件拷贝到另一个文件夹中
*  修改她们的后缀名为.txt,用String的replace方法。
*
*/
public static void main(String[] args)
{
File f = new File("F:\\java\\day20");
copyFile(f);
}

//函数功能:把一个文件夹下面的.java结尾的文件复制到copy文件夹下面并改名
public static void copyFile(File f)
{
//创建一个copy文件加,复制后的文件会被装进来
File copy = new File("copy");
copy.mkdir();

//过滤。java文件
File[] files = f.listFiles(new FilenameFilter()
{
public boolean accept(File f,String name)
{
return name.endsWith(".java");
}
});

//复制文件并改名
for (File fileName : files)
{
BufferedInputStream bis = null;
BufferedOutputStream bos = null;

try
{
bis = new BufferedInputStream(new FileInputStream(fileName));
//把后缀名.java改成.txt
String newName = fileName.getName().replace(".java",".txt");

bos = new BufferedOutputStream(new FileOutputStream(new File(copy,newName)));

byte[] by = new byte[1024];
int num = 0;

while ((num = bis.read()) != -1)
{
bos.write(by,0,num);
}
}
catch(IOException e)
{
throw new RuntimeException("读写出错");
}
finally
{
try
{
if (bis != null)
bis.close();
}
catch(IOException e)
{
throw new RuntimeException("读取关闭出错");
}
try
{
if (bos != null)
bos.close();
}
catch(IOException e)
{
throw new RuntimeException("写入关闭出错");
}
}
}
}
}


四、递归

1、定义

当函数内每一次循环还可以调用本功能来实现,也就是函数自身调用自身。这种表现形式,或者编程手法,称为递归。

2、递归注意事项

a、限定条件。是来结束循环调用,否则是死循环。

b、注意递归的次数,尽量避免内存溢出。因为每次调用自身的时候都会先执行下一次调用自己的方法,所以会不断在栈内存中开辟新空间,次数过多,会导致内存溢出。

</pre><p></p><pre>
/*
需求:列出指定目录下文件或文件夹,包含子目录,即列出指定目录下所有内容(带层次的)。

分析,因为目录中还有目录,只有使用同一个列出目录功能的函数完成即可,在列出过程中出现的还是目录的话,还可以再调用本功能,这就是利用递归原理。

*/
public static void main(String[] args)
{
//关联指定路径
File dir=new File("D:\\list");
//列出关联路径中所有的文件件
FileList(dir,0);
}
//列出指定目录下的所以内容
public static void FileList(File dir,int level)
{
//有层次的输出
System.out.println(getLevel(level)+dir);
level++;
File[] fileArr=dir.listFiles();//获取本目录下的所以文件和目录的路径
//遍历
for (File file : fileArr)
{
if(file.isDirectory())
{
//如果目录下还是目录,则继续调用本函数
FileList(file,level);
}
else
System.out.println(getLevel(level)+file);//显示(列出)文件
}
}
//带层次的列表
public static String getLevel(int level)
{
StringBuilder sb=new StringBuilder();
//每多一级目录,就多输出指定字符
for (int x=level;x>0 ; x--)
{
sb.append("|--");
}
return sb.toString();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: