java I/O 以及文件编码

参考:http://www.blogjava.net/haizhige/archive/2008/08/03/219668.html


总结一下就是:

*stream 是对字节进行操作

*Reader, *Writer 是对字符进行操作,既然是对字符操作,肯定会涉及到解码加码的操作。

import java.util.*;
import java.io.*;


public class testJava {

	/**
	 * @param args
	 */		
	public static void main(String[] args)  {
		try {
			BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("tt"),"utf-8"));//用BufferedReader加速读取
			String line = in.readLine();
			byte [] bytes = line.getBytes("utf-8");
			//打印line的utf-8编码
			for (byte b : bytes)
				System.out.print(b+" ");
			System.out.println();
			for (byte b: bytes)
				System.out.print(Integer.toHexString(b & 0xff) + " ");
			System.out.println();
			//打印line的内部编码,注意,内部已经是unicode编码
			for (int i = 0; i < line.length(); ++i) {
				System.out.print(Integer.toHexString((int)line.charAt(i)) + " ");
			}
			System.out.println();
			in.close();
			
			//直接按照字节读取文件
			FileInputStream fin = new FileInputStream("tt");
			
			int len = fin.available();
			byte [] data = new byte[len];
			fin.read(data);
			
			for (byte b : data)
				System.out.print(Integer.toHexString(b & 0xff) + " ");
			
			fin.close();
			
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		
	}

}

tt文件内容是

我是abc


utf8编码,dos格式,bom头


输出是:

-17 -69 -65 -26 -120 -111 -26 -104 -81 97 98 99 
ef bb bf e6 88 91 e6 98 af 61 62 63 
feff 6211 662f 61 62 63 
ef bb bf e6 88 91 e6 98 af 61 62 63 d a 


如果这个java文件是utf-8编码的,则

String s = "我是abc";
for (int i = 0; i < s.length(); ++i)
System.out.print(Integer.toHexString((int)s.charAt(i))+" ");

System.out.println();

s就已经是unicode编码的了


Integer.toHexString(b & 0xff)

b是一个byte, 如果直接Integer.toHexString(b), 因为参数是int类型的,所以第一步是将b变为int,如果b在0-127之间的,那是没问题,如果b在128-255的,首先检测到符号位是1,就把前面的字节都补全为1,比如b=128 

二进制是 1000 0000

变成整形的二进制是 1111 1111 1000 0000

b & 0xff ,就是b & 0x00ff


1、描述:流是字节数据或字符数据序列。Java采用输入流对象和输出流对象来支持程序对数据的输入和输出。输入流对象提供了数据从源点流向程序的管道,程序可以从输入流对象读取数据;输出流对象提供了数据从程序流向终点的管道,程序通过该管道把数据写到终点。所有的关于输入/输出的类都包含在java.io的包中。
2、File类:它主要关心的是文件的具体属性,而非内容,定义了许多方法,实现对文件的创建、删除等操作。
code:
import java.io.*;
public class Test
{
 public static void main(String args[])throws Exception
 {
  File file1=new File("w1.txt");//在当前目录下
  file1.createNewFile();//得到文件w1.txt
  file1.mkdir();//得到目录w1.txt
  File file2=new File("D:\\javaprogram\\text\\w2.txt");//指定目录
  file2.createNewFile();//得到文件w2.txt
  //用静态字段separator获得系统分隔符,保证程序通用性
  File fDir=new File(File.separator);//作为字符是'\',作为File对象为当前根目录
  String fStr="javaprogram"+File.separator+"text"+File.separator+"w3.txt";
  File file3=new File(fDir,fStr);
  file3.createNewFile();//得到文件w3.txt
  file1.delete();
  file2.delete();
  file3.delete();
  //delete()方法删除文件,调用即删除,而deleteOnExit()是在JVM终止时才删除
  //这样就得以建立临时文件以存储临时数据,临时文件保存在临时文件夹
  //要找临时文件夹,请查看环境变量temp的设置
  for(int i=0;i<5;i++)
  {
   File file=File.createTempFile("wang",".temp");
   file.deleteOnExit();
  }
  Thread.sleep(3000);
  //下面的一段程序将实现,打印指定目录下的.java文件的信息
  File f=new File("d:\\javaprogram");
  if(f.exists())//判断文件是否存在
  {
   if(f.isDirectory())//判断文件是目录还是标准文件
   {
    //调用带参数的listFiles()方法返回满足特定过虑器的
    //此抽象路径名所表示目录中的文件和目录的抽象路径名数组
    File[] fname=f.listFiles(new FilenameFilter()
    {
     //匿名类实现接口FilenameFileter的唯一方法
     public boolean accept(File dir, String name) 
     {
      return name.indexOf(".java")!=-1;
     }
    });
    for(int i=0;i     {
     System.out.println(fname[i]);
    }
   }
  }
  else
  {
   System.out.println("文件夹不存在.");
  }
 }
}

3、字节流:
程序运行中常的I/O操作包括向标准设备输入输出数据和文件输入输出。对于前者,java定义了三个直接使用的流对象:System.err(标准错误输出)、System.out(标准输出)和System.in(标准输入);对于后者,可以使用FileOutputStream和FileInputStream。
code:
import java.io.*;
public class Test
{
 static final String file1="D:\\javaprogram\\w1.txt";
 static final String file2="E:\\database\\w2.txt";
 static final String file3="E:\\wmpub\\w3.txt";
 public static void main(String args[])throws IOException
 {
  /*//关于System.in
  int data;
  while ((data=System.in.read())!=-1)//Ctrl+c结束输入
  {
   System.out.write(data);
  }*/
  //下面的程序段用以向file1文件写入,把其内容的一部分复制到file2
  //再把file2文件完整地复制到file3,并打印出来
  FileOutputStream fos1=new FileOutputStream(file1);
  FileOutputStream fos2=new FileOutputStream(file2);
  FileOutputStream fos3=new FileOutputStream(file3);
  fos1.write("今天是2008年8月3号,离北京奥运会还有5天,心里非常激动啊.".getBytes());
  fos1.close();
  FileInputStream fis1=new FileInputStream(file1);
  fis1.skip(19);//跳过19个字节
  byte[] buf=new byte[fis1.available()];
  fis1.read(buf);
  fis1.close();
  System.out.println(new String(buf));
  fos2.write(buf);
  fos2.close();
  FileInputStream fis2=new FileInputStream(file2);
  while(fis2.available()>0)
  {
   byte[] b=new byte[fis2.available()];
   int let=fis2.read(b);
   if(let==-1)break;
   fos3.write(b,0,let);
  }
  System.out.println("复制成功!");
  fis2.close();
  fos3.close();
  //以下程序段实现了一个图像文件的复制
  FileInputStream a=new FileInputStream("4.jpg");
  FileOutputStream b=new FileOutputStream("3.jpg");
  byte c[]=new byte[a.available()];
  a.read(c);
  b.write(c);
  a.close();
  b.close();
 }
}

4、字符流(FileWriter and FileReader)

import java.io.*;
public class Test
{
 public static void main(String args[])
 {
  //本程序完成从控制台读入文件名,并实现复制
  int length;
  char buf[]=new char[100];
  try
  {
   FileReader in=new FileReader(args[0]);
   FileWriter out=new FileWriter(args[1]);
   length=in.read(buf);
   while(length!=-1)
   {
    out.write(buf,0,length);
    //字符流读取通过read()的返回值判断是否读到文件末尾
    //我刚才忘记加这条语句,文件被一直写,都死机了,重启后一看,写了2.6G
    length=in.read(buf);
   }
   in.close();
   out.close();
  }
  catch (IOException e)
  {
   e.printStackTrace();
  }
 }

5、过滤流之一
    Java利用过滤流可以在读写数据的同时对数据进行处理,以达到性能的改善,提高程序执行效率。将过滤流和某个输入流或输出流(节点流)连接。连接是通过在过滤流的构造方法中指定入口参数——节点流来实现的。
  §BufferedInputStream:
                        FileInputStream fis=new FileInputStream("w1.txt");
                        BufferedInputStream bis=new BufferedInputStream(fis);
                        byte[] buf=new byte[100];
                        int len=bis.read(buf,0,len);
                        System.out.println(new String(buf,0,len));
                        bis.close();
        §BufferedOutputStream:
                        FileOutStream fos=new FileOutputStream("w2.txt");
                        BufferedOutputStream bos=new BufferedOutputStream(bos);
                        bos.write("好好学习,天天向上".getBytes());
                        bos.flush();
                        bos.close();
    也可以是匿名创建:如:BufferedOutputStream bos=new BufferedOutputStream(new FileInputStream("w2.txt")); 
     BufferedReader和BufferedWirter与此类似,不过是分别指定Writer和Reader类型的参数罢了。
一个实例程序:
import java.io.*;
public class Test
{
 public static void main(String[] args)
 {
  try
  {
   FileInputStream in=new FileInputStream(args[0]);
   BufferedInputStream bufIn=new BufferedInputStream(in);
   int limit;
   bufIn.mark(limit=bufIn.available());//在当前位置打上标记
   for(int i=0;i     System.out.print((char)(bufIn.read()));
   System.out.println();
   bufIn.reset();//reset缓冲区标志
   int c;
   while((c=bufIn.read())>=0)System.out.print((char)c);
   bufIn.close();
  }
  catch (IOException e)
  {
   e.printStackTrace();
  }
 }
}

5、过滤流之二基本类型数据传输:DataInputStream和DataOutputStream
import java.io.*;
public class Test
{
 public static void main(String args[])
 {
  try
  {
   DataOutputStream dos=new DataOutputStream(
    new BufferedOutputStream(new FileOutputStream(
     "d://javaprogram//w.txt")));
   dos.writeInt(5);
   dos.writeUTF("你好");
   dos.writeBoolean(true);
   dos.writeDouble(3.1415926);
   dos.writeBytes("ok!");
   dos.writeChars("bye bye");
   dos.close();
   DataInputStream dis=new DataInputStream(
    new BufferedInputStream(new FileInputStream(
        "d://javaprogram//w.txt")));
   //读出的顺序应与写入的顺序一致
   System.out.println(dis.readInt());
   System.out.println(dis.readUTF());
   System.out.println(dis.readBoolean());
   System.out.println(dis.readDouble());
   byte b[]=new byte[3];
   dis.readFully(b);
   for(int j=0;j<3;j++)System.out.print((char)b[j]);
   System.out.println();
   StringBuffer st3=new StringBuffer();
   for(int j=0;j<7;j++)st3.append(dis.readChar());
   System.out.println(st3.toString());
   dis.close();
  }
  catch (IOException e)
  {
   System.err.println(e.toString());
  }
 }
}
6、过滤流之三:I/O流的链接图:
  java I/O 以及文件编码_第1张图片  
7、字节和Unicode字符的桥梁:InputStreamReader、OutputStreamWriter
code:
import java.io.*;
public class Test
{
 public static void main(String[] args)throws IOException
 {
  //文件读写
  FileOutputStream fos=new FileOutputStream("w.txt");
  OutputStreamWriter osw=new OutputStreamWriter(fos);
  BufferedWriter bw=new BufferedWriter(osw);
  bw.write("今天是2008年8月3日,离北京奥运还有5天!");
  bw.close();
  FileInputStream fis=new FileInputStream("w.txt");
  InputStreamReader isr=new InputStreamReader(fis);
  BufferedReader br=new BufferedReader(isr);
  System.out.println(br.readLine());
  br.close();
  //控制台读写
  BufferedReader br1=new BufferedReader(new InputStreamReader(System.in));
  BufferedWriter bw1=new BufferedWriter(new OutputStreamWriter(System.out));
  String strLine,str="";
  while((strLine=br1.readLine())!=null)//Ctrl+c结束输入
  {
   str+=strLine;
   System.out.println(strLine);
  }
  br1.close();
  bw1.write(str,0,str.length());
  bw1.write((int)('\n')); //将回车符输入bw1
  bw1.flush();
  bw1.close();
 }
}
8、管道流:PipedInputStream、PipedOutputStream
      作用:用于线程间的通信,一个线程的pipedInputStream对象从另一个线程的PipedOutputStream对象读取输入,要使管道流有用,必须同时构造管道输入流和管道输出流。
例子(孙鑫老师的例子):
import java.io.*;
class Producer extends Thread
{
 private PipedOutputStream pos;
 public Producer(PipedOutputStream pos)
 {
  this.pos=pos;
 }
 public void run()
 {
  try
  {
   pos.write("Hello,welcome you!".getBytes());
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }
}
class Consumer extends Thread
{
 private PipedInputStream pis;
 public Consumer(PipedInputStream pis)
 {
  this.pis=pis;
 }
 public void run()
 {
  try
  {
   byte[] buf=new byte[100];
   int len=pis.read(buf);
   System.out.println(new String(buf,0,len));
   pis.close();
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }
}
public class Test
{
 public static void main(String args[])
 {
  PipedOutputStream pos=new PipedOutputStream();
  PipedInputStream pis=new PipedInputStream();
  try
  {
   pos.connect(pis);
   new Producer(pos).start();
   new Consumer(pis).start();
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }
}
9、PrintWriter类:创建的输出流可以使用print和println方法,按Unicode字符形式输出,输出的数据可读性较好。
        §打印流建立文本文件:
                                PrintWriter out=new PrintWriter(new FileWriter(1.dat));
                                String str="天呢,我告诉你吧:";
                                char[] z={'北','京','奥','运','会','在'};double g=2008;
                                out.println(st);out.print(z);out.print(g);out.println("年08月08日08时08分08秒");
                                out.close();
        §打印流在屏幕上显示文本
                                PrintWriter out=new PrintWriter(System.out);
                                其余同上,此处略
10、文件的随机读写:RandomAccessFile
import java.io.*;
public class Test
{
 public static void main(String args[])throws Exception
 {
  int lineNo;//读到的行号
  long fp;//文件指针
  BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
  RandomAccessFile raf=new RandomAccessFile("w.txt","rw");
  System.out.println("请输入6个字符串");
  int[] len=new int[12];
  String[] str=new String[12];
  for(int i=0;i<6;i++)
  {
   System.out.println("行号"+(i+1)+":");
   str[i]=br.readLine();
   len[i]=str[i].length();
   raf.write((str[i]+"\n").getBytes());
  }
  while(true)
  {
   fp=0;
   raf.seek(0);
   System.out.println("你要显示第几行?"+"(1--6)");
   lineNo=Integer.parseInt(br.readLine());
   for(int i=1;i
    fp=fp+(long)len[i-1]+1;
   raf.seek(fp);
   System.out.println("第"+lineNo+"行"+":"+raf.readLine());
   System.out.println("继续吗?"+"(y/n)");
   if((br.readLine().equals("n")))break;
  }
  raf.seek(raf.length());
  System.out.println("继续写入6行数据:");
  for(int i=6;i<12;i++)
  {
   System.out.println("行号"+(i+1)+":");
   str[i]=br.readLine();
   len[i]=str[i].length();
   raf.write((str[i]+"\n").getBytes());
  }
  System.out.println("打印12行数据:");
  raf.seek(0);
  for(long i=0;i
  {
   System.out.println(raf.readLine());
  }
  raf.close();
 }
}
11、文件的压缩处理
 实例:
import java.io.*;
import java.util.*;
//ZipInputStream和ZipOutputStream在包java.util.zip中
import java.util.zip.*;
public class Test
{
 public static void main(String args[])throws Exception
 {
  //输入若干文件名,将所有文件压缩为w.zip
  ZipOutputStream zos=new ZipOutputStream(
   new BufferedOutputStream(new FileOutputStream("w.zip")));
  for(int i=0;i
  {
   BufferedInputStream bis=new BufferedInputStream(
    new FileInputStream(args[i]));
   //将每个要压缩的文件称为一个压缩入口,使用ZipEntry生成压缩入口对象
   //使用putNextEntry(ZipEntry entry)将压缩入口加入到压缩文件
   zos.putNextEntry(new ZipEntry(args[i]));
   int b;
   while((b=bis.read())!=-1)
    zos.write(b);
   bis.close();
  }
  zos.close();
  //解压缩文件并显示
  ZipInputStream zis=new ZipInputStream(
   new BufferedInputStream(new FileInputStream("w.zip")));
  ZipEntry z;
  while((z=zis.getNextEntry())!=null)//获得入口
  {
   System.out.println(z.getName());//显示文件初始名
   int x;
   while((x=zis.read())!=-1)
    System.out.write(x);
   System.out.println();
  }
  zis.close();
 }
}
12、编码与解码
 import java.util.*;
import java.nio.charset.*;
public class Test
{
 public static void main(String args[])throws Exception
 {
  //以下程序段打印当前计算机所能处理的标准 charset
  //Charset类位于java.nio.charset包中,此类定义了用于创建解码器和编码器
  //以及检索与 charset 关联的各种名称的方法。此类的实例是不可变的。
  //Charset.availableCharsets()返回一个映射
  //Map是java.util包中的一个接口
  Map m=Charset.availableCharsets();
  //keySet()方法返回此映射中包含的键的 set 视图
  Set names=m.keySet();
  //构造迭代器访问诸元素
  Iterator it=names.iterator();
  while(it.hasNext())
  {
   System.out.println(it.next());
  }
  //Properties 类位于java.util包中,表示了一个持久的属性集
  //System.getProperties()确定当前的系统属性。
  Properties pps=System.getProperties();
  pps.list(System.out);//打印属性
  //将系统文件的标准字符集改为:ISO-8859-1
  //设置的字符集,只是当前JVM上的字符集
  pps.put("file.encoding","ISO-8859-1");
  int data;
  byte[] buf=new byte[100];
  int i=0;
  while((data=System.in.read())!='q')
  {
   buf[i]=(byte)data;
   i++;
  }
  String str=new String(buf,0,1);
  System.out.println(str);
  //ISO-8859-1字符解码为Unicode字符(java使用)
  //Unicode字符编码为GBK字符
  //但并不是所有字符都能反编码回来,比如汉字将丢失高字节
  String strGBK=new String(str.getBytes("ISO-8859-1"),"GBK");
  System.out.println(strGBK);
 }

13、对象序列化
               对象的寿命常随着对象的程序的终止而终止,倘若需要对对象的状态进行保存,需要时再恢复。我们把对象的这种能够记录自己状态以便将来再生的能力,叫做对象的持续性(persistence)。对象通过写出描述自己状态的值——对象转化为字节流,来记录自己的这个过程叫对象的序列化(serialization)。  一个对象要能够实现序列化,必须实现Serializable接口,或者Externalizable接口。 
               一个对象被序列化时,只保存对象的非静态成员变量,如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。但如果把这个引用标记为transient,那么对象仍然可以序列化。
                另外,对象序列化建立了一张对象网,将当前要序列化的对象中所持有的引用指向的对象都包含起来一起写入到文件,如果一次序列化几个对象,它们中的相同内容会被共享。
code:

import java.io.*;

public class Test
{
 public static void main(String[] args) throws Exception
 {
  Employee e1=new Employee("zhangsan",25,3000.50);
  Employee e2=new Employee("lisi",24,3200.40);
  Employee e3=new Employee("wangwu",27,3800.55);
  ObjectOutputStream oos=new ObjectOutputStream(
   new FileOutputStream("w.dat"));
  oos.writeObject(e1);
  oos.writeObject(e2);
  oos.writeObject(e3);
  oos.close();

  ObjectInputStream ois=new ObjectInputStream(
   new FileInputStream("w.dat"));
  Employee e;
  String strSal;
  for(int i=0;i<3;i++)
  {
   e=(Employee)ois.readObject();
   //设置自已需要的输出方式
   //strSal=(e.salary==0)?"不告诉你":String.valueOf(e.salary);
   //System.out.println(e.name+":"+e.age+":"+strSal);
   System.out.println(e.name+":"+e.age+":"+e.salary);
  }
  ois.close();
 }
}
class Employee implements Serializable
{
 String name;
 int age;
 transient double salary;
 transient Thread t=new Thread();
 public Employee(String name,int age, double salary)
 {
  this.name=name;
  this.age=age;
  this.salary=salary;
 }
 //重写方法,完成需要的操作,如果不重写,要想不写入某些数据可以标记为transient
 //本程序的数据salary就被标记为transient,打印时输出为0.0,如果是String将为null
 /*private void writeObject(java.io.ObjectOutputStream oos)throws IOException
 {
  oos.writeUTF(name);
  oos.writeInt(age);
  //System.out.println("Write Object");
 }
 private void readObject(java.io.ObjectInputStream ois)throws IOException
 {
  name=ois.readUTF();
  age=ois.readInt();
  //System.out.println("Read Object");

 }*/

}


Java Unsigned数据类型解决方案

在Java中,不存在Unsigned无符号数据类型,但可以轻而易举的完成Unsigned转换。

方案一:如果在Java中进行流(Stream)数据处理,可以用DataInputStream类对Stream中的数据以Unsigned读取。

        Java在这方面提供了支持,可以用java.io.DataInputStream类对象来完成对流内数据的Unsigned读取,该类提供了如下方法:
         (1)int   readUnsignedByte()    //从流中读取一个0~255(0xFF)的单字节数据,并以int数据类型的数据返回。返回的数据相当于C/C++语言中所谓的“BYTE”。
          (2)int readUnsignedShort()   //从流中读取一个0~65535(0xFFFF)的双字节数据,并以int数据类型的数据返回。返回的数据相当于C/C++语言中所谓的“WORD”,并且是以“低地址低字节”的方式返回的,所以程序员不需要额外的转换。

方案二:利用Java位运算符,完成Unsigned转换。

       正常情况下,Java提供的数据类型是有符号signed类型的,可以通过位运算的方式得到它们相对应的无符号值,参见几个方法中的代码:

主要思想就是用更宽的类型表示窄类型的无符号数值

byte b = (byte)254;
System.out.println(b);//-2
int i = b&0x0ff;
System.out.println(i);//254


在转换的时候要注意,原来的类型时n个字节,就用2*n个f做与运算,并且要在最前面加上0,将窄类型扩展的符号位清零


      public int getUnsignedByte (byte data){      //将data字节型数据转换为0~255 (0xFF 即BYTE)。
         return data&
0x0FF;
      }

      public int getUnsignedByte (short data){      //将data字节型数据转换为0~65535 (0xFFFF 即 WORD)。
            return data&0x
0FFFF;
      }       

     public long getUnsignedIntt (int data){     //将int数据转换为0~4294967295 (0xFFFFFFFF即DWORD)。
         return data&0x0FFFFFFFFl;//在java中,默认字面整数数值都是int类型的,所以要在最后添加l表示是long
      }

        灵活的运用这些技法,根本不存“二进制在Java中得不到全面支持”的论断!


你可能感兴趣的:(java)