读写文件
如果想要数据存储在硬盘中的文件和Web服务器中的文档,可使用java.io包中的类。其中的io表示input/output,这些类用于访问数据源,如硬盘、CD-ROM或计算机内存。可以使用称为流的通信系统,将数据传入程序或从程序中传出数据。
1、流
要在Java程序中永久地保存数据或要检索已储存的数据,至少必须有一个流。流可以连接到各种数据源,包括计算机程序、硬盘、Internet服务器、计算机内存和DVD-ROM。由于他们都使用流,因此学会如何使用其中的一种数据后,就能够以相同的方式处理其他类型的数据。有如下两种类型的流:
>输入流:从数据源读取数据;
>输出流:讲数据写入数据源。
所有输入和输出流都由字节(是0~255的整数)组成,可以用这种格式来表述数据,如可执行程序、字处理文档和MP3音乐文件,但这只是字节可表示的一小部分数据。直接留用于读写这种数据。
字符流是一种更专用的流,顾名思义就是用来读写字符的,特别是读写文本数据源。
无论是使用字节流、字符流还是其他类型的信息,整体过程是相同的:
>创建一个与数据相关联的流对象;
>调用流的方法,将信息加入流中或从流中取出信息;
>调用流对象的close()方法关闭流。
1)、文件
在Java中,文件用File类表示,可以读取硬盘、CD-ROM或其他存储设备中的文件。File对象可表示已有的文件或要创建的文件,如下:
File filename = new File(“xiaowu.txt”);
这条语句在程序所在的文件夹下创建一个叫做xiaowu.txt的文件,也可以在文件中包括路径:
Filefilename = new File(“test01\\data\\xiaowu.txt”);
(注意:上述代码适用于windows系统,因为它使用反斜杠作为文件名和路径的分隔符。要在任何系统都适用,请使用File.pathSeparator,例如:
File name = new File(“test01”+ File.pathSepataor + “xiaowu.txt”);)
有了File对象后,就可以调用该对象的几个有用的方法:
>exist():判断文件是否存在;
>getName():返回文件名;
>getAbsolutePath():获得文件名+文件的的绝对路径
>length():将文件的长度作为long值返回;
>createNewFile():如果文件不存在,创建它;
>delete():如果文件存在,将删除他;
>renameTo(File):适用通过参数指定的File对喜爱那个的名称来重命名文件;
>mkdir()/mkdirs():如果路径中文件夹不存在,则创建最后一个文件夹/路径下的所有文件夹。
也可以使用File对象表示系统中的文件夹而不是文件。为此,在构造函数File中指定文件夹名,这可以使绝对路径(如C:\\MyDocuments\\),也可以是相对路径(如java\\database)。有了代表文件夹的对象后,就可以调用其listFiles()方法来看文件夹的内容。该方法返回一个File对象数组,表示文件夹包含的每个文件和子文件夹。
2)、从流中读取数据
我们可以使用FileInputStream类从文件中读取字节的输入流。要创建文件输入流,可调用FileInputStream()构造函数并将一个文件名或File对象作为参数。注意创建输入流时对应的文件必须存在,否则将引发IOException异常。代码如下:
try { File filePath = new File("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\"); File file = new File(filePath ,"xiaowu.txt"); System.out.println(file.getName() +""); if (!filePath.exists() &&filePath.isDirectory()) { System.out.println("路径不存在"); filePath.mkdirs(); } else { System.out.println("路径存在"); if (!file.exists()) { System.out.println("文件不存在"); file.createNewFile(); FileInputStream stream = newFileInputStream(file); } else{ System.out.println("文件存在"); } } } catch (Exception e) { e.printStackTrace(); }
代码很简单我就不讲了,有人可能会问文件刚创建里面没东西怎么读呢?其实这里是为了演示文件操作的过程才这样写的,这个不用管哈。
读取输入流时,从流中的第一个字节开始读取,如文件的第一个字节。可以调用带有一个参数的skip()方法来跳过一些字节,该参数是一个int参数,表示要跳过的字节数,例如stream.skip(1024)就是跳过流中接下来的1024个字节。
如果要一次读取多个字节,可以这样做:
>创建一个字节数组,其大小等于要读取的字节数;
>使用该数组作为参数调用read()方法,将使用从流中读取的字节填充该数组
下面创建一个读取MP3音频文件的应用程序,并将读取到的内容打印出来:
try { File file = new File("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\", "碎玻璃声.MP3"); FileInputStream fileInputStream =new FileInputStream(file); int size = (int)file.length(); byte[] bt = new byte[128]; String string = ""; while (true) { int temp =fileInputStream.read(bt); if (temp <= 0) break; string += new String(bt); } System.out.println("结果:" + string); } catch (Exception e) { e.printStackTrace(); }finally{ fileInputStream.close();}
3)、缓冲输入流
对于读取输入流的程序,提高其性能的一个方法是将输入放到缓冲区中。缓冲(buffering)是将数据放到内存中供应用程序需要时使用的一个过程。当程序需要缓冲输入流中的数据时,将首先在缓冲区中查找,这比从文件等数据源读取数据快。
要使用缓冲输入流,就要创建一个输入流如FileInputStream对象,然后使用该对象创建缓冲的流。为此,将输入流作为唯一的参数调用BufferedInputStream(InputStream)构造函数,这样从输入流中读取数据时,数据将被存储到缓冲区中。
要从缓冲的流中读取数据,可调用其read()方法且不指定任何参数。这将返回一个0~255的整数,表示该流中下一字节的数据。如果没有字节可读取,将返回-1。
下面是一个使用缓冲流读取文件的例子:
public classJavaApplication1 { public static String readLine() { StringBuffer response = newStringBuffer(); try { File file = new File("D:\\桌面\\桌面\\安卓开发工具\\学习笔记\\碎玻璃声.MP3"); FileInputStream fileInputStream =new FileInputStream(file); BufferedInputStream bin = newBufferedInputStream(fileInputStream); int in = 0; char inChar; do { in = bin.read(); inChar = (char)in; if (in != -1) { response.append(inChar); } } while ((in != -1)); bin.close(); return response.toString(); } catch (Exception e) { System.err.println("Exception:" + e.getMessage()); return null; } } public static void main(String[] args) { String input =JavaApplication1.readLine(); System.out.println(input +""); } }
虽然看起来这段程序跟刚才那段很相似,但效率提高了不知多少倍。
2、将数据写入流中
在java.io包中,与流相关的类都是成对出现的。对于字节流,有FileInputStream类和FileOutputStream类;对于字符流,有FileReader类和FileWriter类,还有很多其他成对的用于处理流数据的类。
要将数据写入字节流中,首先需要创建一个与输出流相关联的File对象。该文件不必是系统中现有的文件。
可以通过两种方式创建FileOutputStream。如果要在现在的文件中追加字节,使用两个参数调用构造函数FileOutputStream:一个是代表文件的File对象,另一个是布尔值true。这样写入流中的字节就会追加到文件的末尾。
如果要讲字节写入一个新文件中,只使用一个File对象作为参数调用构造函数FileOutputStream()。
有了输出流后就可以调用不同的write()方法来写入字节:
>用一个字节作为参数调用write()方法时,将该字节写入流中。
>用一个字节数组作为参数调用write()方法时,将该字节写入流中。
>给write(byte[] , int ,int)方法指定3个参数:一个字节数组、一个表示要写入流中的数组的第一个元素的整数、要写入的字节总数。
下面的语句创建一个包含10个字节的字节数组,并将最后5个字节写入到输出流中:
File data = newFile("data.dat");
FileOutputStream fileOutputStream =new FileOutputStream(data);
byte[] dt = new byte[]{5, 12 , 4 ,13 , 3 , 15 , 2 , 17 , 1 , 18};
fileOutputStream.write(dt , 5 , 5);
将数据写入到流中后,调用流的close()方法关闭它。
String name = “小武灵灵”;
Byte[] name = name.getByte[];
现在编写一个简单的应用程序,他通过将字节写入到文件输出流中的方式,将几行文本存储到一个文件中。代码如下:
public classJavaApplication1 { String newline =System.getProperty("line.separator"); public JavaApplication1() { try { File file = new File("program.properties"); FileOutputStream fileOutputStream =new FileOutputStream(file); write(fileOutputStream,"username = max"); write(fileOutputStream, "score= 12550"); write(fileOutputStream, "level= 5"); } catch (Exception e) { System.err.println("不能写入文件"); } } void write(FileOutputStream stream , Stringoutput) throws IOException { output += newline; byte[] data = output.getBytes(); stream.write(data , 0 , data.length); } public static void main(String[] args) { JavaApplication1 application1 = newJavaApplication1(); System.out.println("完毕"); } }
3、读写配置属性
当使用命令行参数对Java程序进行配置之后,Java程序将更有用。Java.util包中有一个properties类,可用于从源文件中载入配置设置。
在Java中,可以像其他文件那样读取属性文件:
>创建一个代表该文件的File对象;
>使用该File对象创建一个FileInputStream对象;
>调用load()方法从输入流中检索属性。
属性文件有一组属性名、等号和属性值组成,如下所示:
Username = asd
lastCommand = open database
windowSize = 32
每个属性占一行,因此上述内容将属性username、lastCommand和windowSize的值分别设置为asd、open database和32(我们自己建的类也是用相同的格式)
下面的代码载入一个名为config.dat的属性文件:
File configFile = new File("config.dat");
FileInputStream fileInputStream = new FileInputStream(configFile);
Properties config = new Properties();
config.load(fileInputStream);
配置设置也称为属性,作为字符串存储在Properties对象中。每个属性都用一个类似于applet参数的键标识。方法getProperty()根据键来检索属性,如下面的语句所示:
String username = config.getProperty(“username”);
由于属性被存储为字符串,要将其用作数字值,必须采用某种方式对其进行转换,如下面的代码所示:
String windowProp = config.getProperty(“windowSize”);
Int windowSize = 24;
Try{
windowSize = Integer.parseInt(windowProp);
}catch(NumberFormatException exception){}
要存储属性,可调用setProperty()方法并指定两个参数——键和值:
Config.setProperty(“username” , “asd”);
可以调用Properties对象的list(PrintStream)方法来显示所有的属性。PrintStream是System类中out类的变量。下面的代码将调用list()方法来显示所有的属性。
Config.list(System.out);
在对属性做出修改之后,可将其存回到文件中:
>创建一个代表文件的File对象;
>根据该File对象创建一个FileOutputStream个;
>调用方法store(OutputStream , String)将属性存储到指定的输出流中,而且参数String是属性文件的描述。
接下来创建一个ConfigWrite应用程序,它将多个文件属性设置写入到一个文件中。而Configurator应用程序将这些属性设置读入到一个Java属性文件中,并添加一个名为runtime的心属性(具有当前日期和时间),然后保存该文件。下面是全部代码:
package javaapplication1; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Date; import java.util.Properties; public class Configurator { public Configurator() { try { //载入properties文件 File configFile = new File("program.properties"); FileInputStream fileInputStream = new FileInputStream(configFile); Properties config = new Properties(); config.load(fileInputStream); //创建一个新的property Date current = new Date(); config.setProperty("runtime", current.toString()); //保存properties文件 FileOutputStream fileOutputStream = new FileOutputStream(configFile); config.store(fileOutputStream, "Properties settings"); fileInputStream.close(); config.list(System.out); } catch (Exception e) { System.out.println("IO error" + e.getMessage()); } } public static void main(String[] args) { Configurator configurator = new Configurator(); } }
打开文件program.properties应该包含如下文本:
#Properties settings
#Fri Mar 22 00:14:38 CST 2013
runtime=Fri Mar 22 00\:14\:38 CST 2013
score=12550
level=5
username=max