Java基础之IO流
File类
文件和目录路径名的抽象表示形式。用来将文件或者文件夹封装成对象。方便对文件或文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数。流只能操作数据,而File对象可以操作文件或文件夹的属性信息。
示例:File f = new File("a.txt");将a.txt封装成File对象,可以将已存在的和未存在的文件或文件夹封装成对象。
String separator:该字段是一个跨平台的分割符,返回一个字符串类型。示例:String s = File.separator;
File类常见方法:
1.创建:
boolean createNewFile():在指定位置创建文件,如果该文件已经存在则不创建,返回创建false。该方法和输出流不
同,输出流对象一建立就创建文件,并且文件已存在会被覆盖。
boolean mkdir():创建一级文件夹。 boolean mkdirs():创建多级文件夹。
2.删除:
boolean delete():删除指定的文件或目录。如果删除失败则返回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值,以毫秒为单位。
long length():获取该文件对象的大小(长度),以字节为单位。
boolean renameTo(File dest):重新命名此抽象路径名表示的文件。
示例:f1.renameTo(f2):将f1的文件名改成f2的文件名。代码演示:
import java.io.*;
class FileDemo1
{
public static void main(String[] args) throws IOException
{
File f = new File("FileDemo1.java");
sop(f.createNewFile()); //在指定位置创建文件
sop(f.delete()); //删除指定的文件或目录。
f.deleteOnExit(); //在程序退出时删除指定的文件,在虚拟机终止时删除指定的文件或目录
sop(f.mkdirs()); //创建多级文件夹
sop(f.canExecute()); //判断该文件对象是否可以执行
sop(f.exists()); //判断文件是否存在。
sop(f.isFile()); //判断指定的文件对象是否是文件
sop(f.isDirectory()); //判断指定的文件对象是否是目录
sop(f.isHidden()); //判断指定的文件对象是否是隐藏文件
sop(f.isAbsolute()); //判断指定的文件对象是否是绝对的
sop(f.getPath()); //获取路径名称
sop(f.getParent()); //获取该文件对象的父路径名称
sop(f.getAbsolutePath()); //获取该文件对象的绝对路径名称
sop(f.lastModified()); //返回该文件对象最后一次被修改的时间
sop(f.length()); //获取该文件对象的大小(长度)
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
File[] listRoots():列出可用的文件系统根目录,也就是说列出电脑中有效的盘符。返回的是一个File[],File[]
files = File.listRoots(); 代码示例:
import java.io.*;
class FileDemo2
{
public static void main(String[] args)
{
File[] files = File.listRoots();
for(File f : files) //列出电脑中有效的盘符
{
System.out.println(f);
}
File f = new File("D:\\java2014");
String[] names = f.list();
for(String s : names)
{
System.out.println(s);
}
}
}
String[] list():返回的是指定的目录下的文件和文件夹的名称,包括隐藏的文件。
示例:File f = new File("D:\\java2014"); String[] names = f.list() 。
需要注意:调用list方法的File对象必须封装了一个存在的目录。
File[] listFiles():返回的是指定的目录下的文件和文件夹的对象数组 ,包含隐藏的文件。
示例:File f = new File("D:\\java2014");File[] file = f.listFiles()。
该方法返回的是File[],File[]中存放的是File对象,方便于对File对象的操作,因此建议开发用此方法。
/*
需求:列出指定目录下的文件或者文件夹,包含子目录中的内容。也就是该目录中的所有的文件。
*/
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = new File("d:\\java2014");
showDir(dir);
//System.out.println(getSum(1000));
}
public static void showDir(File dir)
{
System.out.println(dir);
File[] files = dir.listFiles();
for(int x =0; x<files.length; x++)
{
if(files[x].isDirectory()) //判断是否是文件夹,如果是,那么继续递归
showDir(files[x]);
else
System.out.println(files[x]);
}
}
}
String[] list(FilenameFilter filter):传入一个FilenameFilter对象,该对象要实现FilenameFilter接口,并且要覆
盖boolean accept(File dir,String name) 方法,该方法测试指定的文件名是否包含在指定的目录中。
如果包含在目录中则返回true,否则返回false。方法中的内容可以定义为return name.endsWith(".java") 。
可以不传FilenameFilter对象,最好是传入一个匿名内部类。
递归:函数自己调用自己。应用场景:当某一功能要重复使用时。
注意:递归时一定要明确结束条件。要注意递归的次数,尽量避免内存溢出。代码示例:
/*
练习:将一个指定目录下的java文件的绝对路径存储到一个文本文件中。
思路:
1.对指定的目录进行递归。
2.获取递归过程中所有的java文件的绝对路径。
3.将java文件存储到集合中。
4.将集合中的数据写入到一个文本文件中。
*/
import java.io.*;
import java.util.*;
class JavaFileList
{
public static void main(String[] args)
{
File dir = new File("d:\\java2014");
List<File> list = new ArrayList<File>();
fileToList(dir,list);
//System.out.println(list.size());
File file = new File("d:\\java2014\\JavaFileList.txt");
writeToFile(list,file);
}
public static void fileToList(File dir,List<File> list)
{
File[] files = dir.listFiles();
for(File f : files)
{
if(f.isDirectory())
fileToList(f,list);
else
{
if(f.getName().endsWith(".java"))
list.add(f);
}
}
}
public static void writeToFile(List<File> list,File file)
{
BufferedWriter bufw = null;
try
{
bufw = new BufferedWriter(new FileWriter(file));
for(File f : list)
{
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("数据写入失败");
}
finally
{
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException("流资源关闭失败");
}
}
}
}
Properties:
Properties是Hashtable的子类,也就是Map集合的一个子类对象,所以可以通过Map集合的方法取出该集合中的元素。
迭代Properties集合获取键和值,获取所有的属性信息。该集合中存储的都是字符串,没有泛型定义。
是集合与IO技术相结合的集合容器。可以用于键值对形式的配置文件,并且可以将属性信息存储到硬盘上。
数据的固定格式是:键=值 。
setProperty(key,value):设置属性信息。
String getProperty(key):通过键获取值。
Set<String> stringPropertyNames():获取此属性列表中的键集,其中该键及其对应值是字符串。
代码示例:
class Demo
{
public static void main(String[] args) throws IOException
{
Properties prop = new Properties();
prop.setProperty("zhangsan","22");
prop.setProperty("lisi","25");
String value = prop.getProperty("lisi");
//prop.list(System.out);
Set<String> set = prop.stringPropertyNames();
for(String key : set)
{
System.out.println(key+":"+prop.getProperty(key));
}
}
}
load(InputStream inStream):从输入流中读取属性列表(键和元素对)。
示例:prop.load(new FileInputStream("Info.txt")),将流中的数据加载进Properties集合。
load(Reader reader):示例:prop.load(new FileInputStream("Info.txt")),将流中的数据加载进Properties集合。
list(PrintStream out)和list(PrintWriter out) :将属性列表输出到指定的输出流。示例:prop.list(System.out),
打印集合中元素。
store(OutputStream out, String comments):将此Properties集合中的属性列表(键和元素对)写入输出流。
示例:FileOutputStream fos = new FileOutputStream("Info.txt"); prop.store(fos,"注释信息");
代码示例:
import java.io.*;
import java.util.*;
/*
需求:将流中的数据存储到集合中,将info.txt中的数据存入到Properties集合中。
思路:1.用一个流和文件相关联。2.读取一行数据,用"="进行切割。3.将"="左边作为键,右边作为值,
存储到集合中即可。
*/
class Test
{
public static void main(String[] args) throws IOException
{
BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
Properties prop = new Properties();
prop.load(bufr); //将流中的数据加载进集合。
prop.setProperty("lisi","30");
BufferedWriter bufw = new BufferedWriter(new FileWriter("info.txt"));
prop.store(bufw,"amen"); //将集合中的数据加载到流中。
/*
for(String line=null; (line=bufr.readLine())!=null; )
{
String[] arr = line.split("=");
prop.setProperty(arr[0],arr[1]);
}
*/
prop.list(System.out); //打印属性列表。
bufr.close();
bufw.close();
}
}
打印流(PrintStream、PrintWriter):提供了打印方法,可以将各种数据类型的数据都原样的打印。
字节打印流:PrintStream
构造函数可以接收的参数类型:
1.file对象:File 。2.字符串路径:String 。3.字节输出流:OutputStream 。
字符打印流:PrintWriter
构造函数可以接收的参数类型:
1.file对象:File 。2.字符串路径:String 。 3.字节输出流:OutputStream 。4.字符输出流:Writer
PrintWriter(OutputStream out, boolean autoFlush):如果为 true,则 println、printf或format方法将刷新输出缓冲
区。自动刷新。
序列流:SequenceInputStream ,将多个读取流合并成一个读取流。
Vector<FileInputStream> v = new Vector<FileInputStream>();v.add(new FileInputStream("f:\\1.txt"));
v.add(new FileInputStream("f:\\2.txt"));Enumeration<FileInputStream> en = v.elements();SequenceInputStream
sis = new SequenceInputStream(en);FileOutputStream fos = new FileOutputStream("f:\\4.txt"); 代码示例:
class Test
{
public static void main(String[] args) throws IOException
{
//创建一个Vector集合
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("1.txt")); //将流对象存储到Vector集合中。
v.add(new FileInputStream("2.txt"));
v.add(new FileInputStream("3.txt"));
v.add(new FileInputStream("4.txt"));
Enumeration<FileInputStream> en = v.elements(); //获取集合的迭代器
//创建合并流对象,接收一个枚举。
SequenceInputStream sis = new SequenceInputStream(en);
PrintWriter out = new PrintWriter(System.out);
for(int by=0; (by=sis.read())!=-1; )
{
out.print((char)by);
}
sis.close();
out.close();
}
}
切割文件:day16\SplitFile.java 。第20天-17。
对象的序列化:操作对象。ObjectInputStream与ObjectOutputStream 。被操作的对象需要实现Serializable (标记接口)。管道流:PipedInputStream和PipedOutputStream 。输入输出可以直接进行连接,通过结合线程使用。
RandomAccessFile 类:随机访问文件,自身具备读写的方法。通过skipBytes(int x),seek(int x)来达到随机访问。随机存取文件的行为类似存储在文件系统中的一个大型字节数组。该类直接继承Object类,但它是IO包中成员,因为它具备读和写功能。内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer方法获取指针位置,同时可以通过seek方法改变指针的位置。该类完成读写的原理就是内部封装了字节输入流和输出流。通过构造函数可以看出该类只能操作文件,而且操作文件还有模式:只读r ,读写rw 等模式。如果为只读模式r,不会创建文件,会去读取一个已经存在的文件,如果该文件不存在,则会出现异常。如果模式为rw,若操作的文件不存在,会自动创建文件,如果存在则不会覆盖。该类要掌握的特点:1.有模式r、rw,2.可以直接读取或写入基本数据类型:readInt()、writeInt() 。3.可以通过seek方法改变指针的位置,来进行指定的数据读取和写入。
DataInputStream与DataOutputStream:用于操作基本数据类型的流对象。凡是操作基本数据类型就用它。
DataOutputStream:构造函数:DataOutputStream(OutputStream out)。写的方法:writeBoolean(boolean v)、writeDouble(double v)、writeInt(int v) 。示例:DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt")); dos.writeBoolean(true); dos.writeDouble(35.45);dos.writeInt(99);
DataInputStream:构造函数:DataInputStream(InputStream in)。读的方法:readBoolean() 、readDouble()、readInt()。怎么写入的就怎么读取出来顺序不能错误,否则会出现乱码情况。
ByteArrayInputStream与ByteArrayOutputStream :用于操作字节数组的流对象。
ByteArrayInputStream :在构造的时候需要接收数据源,并且数据源是一个字节数组。ByteArrayOutputStream :在构造的时候不用定义数据目的,因为该对象内部已封装了可变长度的字节数组,这就是数据目的地。
这两个流对象操作的都是数组,并没有使用系统资源,所以不用关闭流资源操作。 源设备:内存 ArrayStream、硬盘 FileStream、键盘 System.in。 目的设备:内存 ArrayStream、硬盘 FileStream、控制台 System.out 。
用流的读写思想来操作数组:设置(set)数组是写-->>OutputStream,获取(遍历)数组是读-->>InputStream 。
CharArrayReader与CharArrayWriter :操作字符数组的流对象。 StringReader与StringWriter :操作字符串的流对象。
字符编码
字符流的出现不但为了方便操作字符,更重要的是加入了编码转换。通过转换流:InputStreamReader和OutputStreamWriter来完成编码转换,这两个对象进行构造的时候可以加入字符集。
编码表的由来:计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字,就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
转换流的编码应用:可以将字符以指定编码格式存储。可以对文本数据指定编码格式来解读。指定编码表的动作由构造函数完成。
编码:字符串-->>字节数组:通过String类的byte[] getBytes()方法,该方法里面可以传递一个字符集,表示按着什么编码表进行编码,
byte[] getBytes(String charsetName)。示例:byte[] by = str.getBytes(); byte[] by = str.getBytes("UTF-8");
解码:字节数组-->>字符串:通过String的构造函数:new String(byte[] buf),构造函数里面也可以传递一个字符集,表示按着什么编码表进行解码,new String(byte[] by,String charsetName)。示例:String st = new String(byte[],"GBK") 。