数据怎么传递?
在两个终端之间A和B。没有直接的网络连接,那么如果要进行A到B的数据传递,可以通过中间介质来进行中介传递:通过移动U盘把数据从A上拷贝下来,然后再备份到B上,这时,两者通过间接的连接达到传递的目的。而这些数据在系统中是具体的,例如一个文本文件,文本中内容是一份人员表单,其中记录着一次聚会的人员名单,及聚会的时间,地点等信息。对于计算机来说这些数据就是二进制数据,而对于计算机应用者来说,这些数据是我们可见的,字符串类型的内容。
在.net下,如何实现对文本文件的复制与保存的,是如何实现对字符串的读写的?
(1)创建字符串并存在为文本
public void TestCreateText()
{
string strContent = "这是一个文本file。";
StreamWriter writer = File.CreateText(@"k:\myText.txt");
writer.WriteLine(strContent);
writer.Close();
}
现在在文本中记录一个字串:这是一个文本file。
通过IO进行创建文本,并向文本中写入字符串。实现很简单,过程很明了。
(2)读取文本文件,并打印文本内容
public void TestReadText()
{
string strContent = string.Empty;
StreamReader reader = File.OpenText(@"k:\myText.txt");
strContent=reader.ReadToEnd();
reader.Close();
Console.WriteLine(strContent);
}
(3)保存客户信息到文本文件
其中的客户信息被封装到一个客户类实例中,那么如何保存?
public void TestWriteCustomerText()
{
Customer customer = new Customer
{
Unid = 1,
CustomerName = "Songjiang",
CreateTime = DateTime.Now,
Telephone = new Call
{ Mobile = "1111111",
FirmCall = "2222",
HomeCall = "3333" }
};
StreamWriter writer = File.AppendText(@"k:\myText.txt");
writer.WriteLine(customer);
writer.Close();
}
这种方法不可以的,因为StreamWriter的WriteLine方法重载的object方法向文件写入的是并不是customer的内容。如果要写入这个客户实例的内容,包括标识,姓名,创建时间等信息,只能想可以解决的方法,例如把这些信息以字符串来表示,然后就可以写入文本了。
可以这样:
(1)直白的记录
writer.WriteLine("unid:"+customer.Unid);
那么在读取的时候,例如从文本中显示,还要通过一些方法来解析。如果只是单纯的读取文本,可能它并不能明确的表示意义,例如这个文本读取的内容是:unid:1(尽管这里可以看出并知道它表示unid是1)。如果可以把它还原为一个客户实例,那么可以说,它是有意义的(至少在一定范围内,它是有意义的,最起码它确实表示一个客户的unid)。
(2)通过Json来实现
Json可以明确的解析,尽管它的文本意义不能很好的表示(至少不能一目了然),但这种方法是可以满足以上的要求。
public void TestJsonWriter()
{
Customer customer = new Customer
{
Unid = 1,
CustomerName = "Songjiang",
CreateTime = DateTime.Now,
Telephone = new Call {
Mobile = "1111111",
FirmCall = "2222",
HomeCall = "3333" }
};
DataContractJsonSerializer ds =
new DataContractJsonSerializer(typeof(Customer));
FileStream fs = new FileStream(@"k:\myText.txt", FileMode.Open);
ds.WriteObject(fs, customer);
fs.Close();
}
能过对客户实例进行Json化(可以说Json序列化),然后生成json串,进行文本保存。
Json序列化和反序列化有很多种实现方法,在.net3.5中提供了json序列化和反序列化的实现。它的名字空间是:
System.Runtime.Serialization.Json
类库文件为:System.ServiceModel.Web.dll
更多序列化和json序列化内容请见:
http://www.cnblogs.com/jams742003/archive/2010/03/03/1677288.html
下边通过读取json字串,转换为json对象,最终转换为客户类实例:
public void TestJsonReader()
{
Customer customer = new Customer();
DataContractJsonSerializer ds =
new DataContractJsonSerializer(typeof(Customer));
FileStream fs = new FileStream(@"k:\myText.txt", FileMode.Open);
customer=(Customer)ds.ReadObject(fs);
fs.Close();
Console.WriteLine(customer.Unid);
}
这种json序列化保存的客户数据(Customer类的一个实例,一个客户信息)是有规则的,这个规则对于两方(序列化和反序列化)来说是约定好的,这种约定使得双方都可以通过这种约定保存或读取数据,并使数据有意义。
(3)文本的二进制
一个文本文件对于我们来说是一个可以直接读的文本内容,一个大字符串,但在电脑上保存时(物理上),它是以二进制格式进行保存的。
例如:得到abc这个字符串的二进制
在Ascii码环境下,abc这个字符串的二进制是:
97 98 99
1100001 1100010 1100011
对于文本文件是如何读取的?例如通过记事本来打开上边用到的那个文本。
·得到这个文本的二进制流
·得到这个文件的字符编码,文本文件默认的是ANSI编码,在中文系统下,它就是GB2312编码。
·解释流
――――――――――――――――――――――――
{"CreateTime":"\/Date(1269854982203+0800)\/","CustomerName":"Songjiang","Telephone":{"FirmCall":"2222","HomeCall":"3333","
――――――――――――――――――――――――
这是一长字符串,里边没有127以后的字符,即它们都属Ascii码范围。它的二进制就是分别得到这些Ascii字符的二进制。
例如:前三个{“C这三个字符的编码,通过Ascii码表:123 34 67这时10进制,在16进制下是:7b 22 43
用ultra打开这个文本文件,并查看16进制就是:7b 22 43。(在有些编码环境下,文本文件前有多余的字符,叫做BOM)
图片文件在物理上也是二进制格式存储的,但在电脑上可以看到这些二进制所表示的内容(一张图片)。用记事本打开一张gif。是一堆的乱码,但前三个gif是认识的。记事本默认ANSI编码,在中文系统下是GB2312编码。
(4)文本文件中的图文混排
现在把一张gif图与一些文本以文本格式存在一起。为简单起见,文本内容为:
A然后是图片的二进制。
首先说明一下图片如果用记事本打开看到的乱码的问题:对于二进制来说,图片读到流,然后写到字节数组中。我的操作系统是win2003,记事本默认的字符编码格式为ANSI,在中文系统下代表GB2312,所以从记事本打开图片的通过GB2312字符编码对字节数组的解析。
public void TestAscii()
{
StreamWriter writer = File.CreateText(@"k:\MixTest.txt");
FileStream fileStream = new FileStream(@"k:\x1.gif", FileMode.Open);
BinaryReader reader = new BinaryReader(fileStream, _encoding);
byte[] bb=new byte[fileStream.Length];
reader.Read(bb, 0, bb.Length);
Encoding encoding = Encoding.GetEncoding(936);
string strTemp = encoding.GetString(bb);
reader.Close();
fileStream.Close();
writer.WriteLine(strTemp);
writer.Close();
}
那么图片就被保存成了GB2312字符串。这个过程不可逆,因为其中的转换可能不是包含的关系。例如:FF在Ascii码环境下就会被?号所代替,然后还有其它例如BOM等因素,所以这种在GB2312下转换图片是不可逆的。(乱码不可怕,乱码其实不乱,它只是所在的字符集中的字符而已,但未转换前可能不是这个样子)
如果要把图片保存为文本串要保证:
·对于00到FF间的字节都要有正确的表示,Ascii码就不行
·一定要是一个字节是一个字节。意思就是整个数组不能中间添加其它的字节
解决方法:
第一步,通过找00到FF之间存在的都是一个字节的字符编码来实现,例如:ISO/IEC 8859-1字符集,它是第一个8位字符集,而ascii是7位的,只能表示0—127。8859-1的代码页为:28591。
第二步,对字节进行Base64类似的变换。让中文下的环境支持编码,不要添加或删除字节。
写入到文本中的顺序是:ISO8859-1字串——Base64字串——gb2312串(默认)
从文本到图片的顺序是:gb2312字串(默认)——Base64字串——ISO8859-1字串
写入到文本:
public void TestReadPic()
{
//1 iso串
Encoding _encoding = Encoding.GetEncoding(28591);
StreamReader sr = new StreamReader(@"k:\x1.gif", _encoding);
string strTemp=sr.ReadToEnd();
sr.Close();
//2 base64串
byte[] bb = _encoding.GetBytes(strTemp);
string strBase64 = Convert.ToBase64String(bb);
StreamWriter writer = File.CreateText(@"k:\MixTest.txt");
writer.Write(strBase64);
writer.Close();
}
保存的Base64字串(ANSI编码下,在中文系统中,ANSI指GB2312)中的一段:
R0lGODlhZABkAPcAAAAAM8FvZ2ItH//pvF0qIHpQbjMzM/
LNr2tjQ4GAntKypPDp60lCRmg2KTQYUh4E
……
然后是从文本文件到图片:
public void TestWritePic()
{
//1 base64串
Encoding _encoding = Encoding.GetEncoding(936);
StreamReader sr = new StreamReader(@"k:\MixTest.txt", _encoding);
string strBase64 = sr.ReadToEnd();
sr.Close();
//2 ISO串
byte[] bb = Convert.FromBase64String(strBase64);//iso字节
Encoding encoding = Encoding.GetEncoding(28591);
string strReturn = encoding.GetString(bb);
FileStream fs = File.Create(@"k:\MixTest3.gif");
fs.Write(bb, 0, bb.Length);
fs.Close();
}
图片是正常的。
图文混排的方式也在以上的基础上实现了。
以上就是数据存放的方式,以及在.net环境下进行的字符编码以及流之间的转化工作。