------- android培训、java培训、期待与您交流! ----------
IO流用来处理设备之间的数据传输,java的操作流按操作数据分为字节流与字符流。按流向分为输出流和输入流。
字符流。
创建一个FileWriter对象,该对象一被初始化就必须明确被操作的文件。该文件会被创建在指定目录下,如果该目录下有同名文件,将被覆盖。
FileWriterfw=new FileWriter(“test.txt”,true);//创建一个文件test.txt;true代表如果该文件存在,则在文件的结尾处续写。
fw.write(“abcd”);//调用writer方法,将数据abcd写入到流里。
fw.flush();//将数据刷到目的文件中
fw.close();//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据,在我们对IO的操作一定不要忘记关闭流对象,防止内存泄露
创建一个文件度分区流对象,和指定名称的文件相关联。要保证该文件存在,如果不存在,会发生异常FileNotFoundException。read方法一次读一个字符,而且会自动往下读。返回值为int,需要强转为char类型。读到结尾处会返回-1。亦可以用read(char[])方法,返回值为存入char数组的元素个数,当返回值为-1时停止。
FileReader fr = newFileReader("a.txt");
FileWriter fw = newFileWriter("b.txt");
char[] chs = new char[1024];
int len = 0;
while((len=fr.read(chs))!=-1)
{
fw.write(chs,0,len);
fw.flush();
}
复制文件的原理就是读取文件和写入文件。为了提高效率,我们采用了BufferedWriter和BufferedReader两个字符缓冲区,代码如下:
import java.io.*;
class Day19
{
publicstatic void main(String[] args)
{
BufferedReaderbr=null;//定义在成员位置是为了让该变量可以作用于整个类
BufferedWriterbw=null;
try
{
br=newBufferedReader(new FileReader("Demo.txt"));
bw=newBufferedWriter(new FileWriter("Demo_copy.txt"));
Stringstr=null;
while((str=br.readLine())!=null)
{
bw.write(str);
bw.newLine();//读取流遇到回车符即停止返回的字符串不带回车
bw.flush();
}
}
catch(IOException e)
{
thrownew RuntimeException("读写错误");
}
finally
{
try
{
if(br!=null)
br.close();
}
catch(Exception e)
{
thrownew RuntimeException("读写关闭错误");
}
try
{
if(bw!=null)
bw.close();
}
catch(Exception e)
{
thrownew RuntimeException("读写关闭错误");
}
}
}
}
字节流。
字节流用的是FileInputStream和FileOutputDream。用法与字符流基本相同。字节流的缓冲区类是BufferedInputStream和BufferedOutputStream。另外有一个类是用来将字节流转换为字符流,例如InputStreamReader isr=new InputStreamReader(new InputStream())。我们可以用字节流来复制一些数据性文件,比如复制一个mp3文件。
BufferedInputStream bfis=newBufferedInputStream(new FileInputStream("d:\\test.mp3"));
BufferedOutputStream bfos =newBufferedOutputStream(new FileOutputStream("d:\\args.mp3"));
byte[] by=new byte[1024];
int len=0;
while ((len=bfis.read(by))!=-1) {
bfos.write(by, 0, len);
bfos.flush();
}
bfis.close();
bfos.close();
}
}
我们可以将它应用于在键盘输入一段字符,因为键盘就是字节流,然后将他打印出来需要按照字符来读取,这就用到了转换流的程序。
字节转换为字符流InputStreamReader:
字节流:InputStream is = System.in;
转换流:InputStreamReader isr = new InputStreamReader(is);
字符缓冲流:BufferedReader br = new BufferedReader(isr);
字符流转化为字节流:OutputStreamWriter
缓冲流:BufferedWriter bw = new BufferedWriter(osw);
转换流:OutputStreamWriter osw = new OutputStreamWriter(os);
字节流:OutputStream os = System.out;
这里需要说的是转换流的参数中可以传入编码表参数,常用的中文编码表有GBK和utf-8。如果我们用不用的编码表编码和解码那么就会出现乱码的现象。如
InputStreamReader isr=newInputStreamReader(“1.txt”,”GBK”)//用GBK编码
OutputStreamWriter osw=newOutputStreamWriter(“2.txt”,”utf-8”)//用utf-8解码
这样就会出现乱码,转换流默认的编码表示GBK。
常见的编码表。
ASCII:美国标准信息交换码。(用一个字节的7位可以表示)
ISO8859-1:拉丁码表,欧洲码表。(用一个字节的8位表示)
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。(所有文字都用两个字节来表示,Java语言使用的就是Unicode)
UTF-8:做多用三个字节来表示一个字符。
那么在控制台上输出我们键盘输入的文字就是先把字节流转换为字符流读取到内存,再从内存读取字符转换为字节流打印在控制台上。
import java.io.*;
class Demo
{
publicstatic void main(String[] args) throws Exception
{
BufferedReaderbr=new BufferedReader(new InputStreamReader(System.in));
Stringline=null;
while((line=br.readLine())!=null)
{
if(line.equals("over"))
break;
System.out.println(line);
}
}
}
如果读取数据直接往目标文件里面写的话直接用字符流FileWriter就可以完成操作。
该采用什么流对象的分析过程。
1、明确源数据为InputStream还是Reader,目的数据为OutputStream还是Writer。
2、是否为文本文件。
3、设备:硬盘、内存、控制台(输出需要用到转换流)、键盘(输入需要用到转换流)。
4、是否需要优化。转换流是字符和字节之间的的桥梁,一般涉及到字符编码转换时需要用到转换流。
File类
根据java万物皆对象的思想,我们将文件也封装成对象,将对文件的共性方法提取出来方便我们操作文件。
构造方法
File file = newFile("c:\\it.txt"); 绝对路径,如果没有扩展名则为目录文件
File file = new File("it.txt"); 相对路径
File file = newFile("c:\\","it.txt");\\两个参数,第一个是绝对路径,第二个是文件名
File file2 = newFile(file,"it.txt");//在指定file对象下建立
file的常用方法:
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,不会覆盖,而是返回false。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
boolean delete():删除失败返回false
void deleteOnExit():在程序退出时删除指定文件。
boolean exists() :文件是否存在.
isFile():判断是否为文件
isDirectory():判断是否为目录,首先要判断是否存在
isHidden():判断是否为隐藏文件,首先要判断是否存在
isAbsolute():判断是否为绝对路径
getName():获取文件名字
getPath():获取文件路径
getParent():获取文件父目录
getAbsolutePath():获取文件绝对路径
long length():获取文件大小,单位为字节数
File[] static listRoots:获取硬盘的所有盘符集合
String[] list:获取指定目录下所有文件和文件夹的名称的字符串数组
File[] listFiles:获取指定目录下所有文件和文件夹的File对象的数组,注意和list的区别,通常根据需要来选择
String[] list(new FilenameFilter):用文件文件名称过滤器得到符合标准的文件
File[] listFiles(new FilenameFilter):文件名称过滤器
关于文件过滤器,我们可以通过内部类的方式来实现,
File file = new File("c:\\");
String[] files = file.list(newFilenameFilter(){
public boolean accept(File dir,String name)
{
if(name.isDirectory)
return false;//如果是目录文件也可能是.java结尾,所以要先排除掉
return name.endsWith(".java");
}
});
以上代码实现了将c盘目录下的所有java文件取出。并封装一个字符串数组中。我们可以把这个字符串数组遍历打印,但是如果我想得到这个文件目录下所有的文件列表,即包括子文件夹中文件和子文件夹中的文件夹中的文件。这就要用到了递归。
递归其实就是一个函数自己调用自己。但是使用递归一定要注意限定条件,另外还有要注意递归的次数,如果过于多,造成内存溢出。
下面为练习代码。
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = newFile("d:\\testdir");
showDir(dir,0);
}
public static String getLevel(int level)//带层次的。
{
StringBuilder sb = new StringBuilder();
sb.append("|--");
for(int x=0; x<level; x++)
{
sb.insert(0,"| ");//根据传入的level返回一个带相应长度的字符串
}
return sb.toString();
}
public static void showDir(File dir,intlevel)
{
System.out.println(getLevel(level)+dir.getName());//因为能执行到这里的文件类型都是文件夹类型,就先把目录级别想对应长度的字符串和目录打出来
level++;//下一级的话就要获得更长的字符串
File[] files = dir.listFiles();
for(int x=0; x<files.length; x++)//遍历文件目录中文件
{
if(files[x].isDirectory())//如果是文件夹,就继续调用本方法,并把相应的level传给他
showDir(files[x],level);
else
System.out.println(getLevel(level)+files[x]);//如果不是就打印
}
}
}