Java作为一种编程语言如此普及的原因之一是它解决了其他语言中常见的I/O网络操作中非常困难的问题C#语言也采用了与Java类似的方法提供了一些库来完成对I/O和网络的操作并隐藏了其复杂的实现方法本篇文章将着重讨论C#中与I/O网络操作有关的名字空间以及这些库的一些模板的通用用法为了方便熟悉Java的编程人员更好地掌握C#使广大读者能够对二种语言进行比较在本篇文章中我们也都给出了相同功能在Java中的实现方法
理解流操作
Java和C#中的流通常与从控制台文件系统或网络读取数据或向这些设备写数据有关在这二种语言间如果程序需要移动或对许多字节的数据进行操作都会较多地用到流操作
Java提供了二个抽象类javaioInputStream和javaioOutputStream其中包括一些允许程序读或写流数据的方法C#则把这二个类合并为一个SystemIOStream与有一个用于读流数据一个用于写流数据的二个对象不同C#中的Stream对象需要通过测试CanRead CanWrite属性对其读写能力进行检测
同步I/O操作
同步I/O操作在这二种语言中是十分相似的无论是Java中的javaioInputStream和 javaioOutputStream还是C#中的SystemIOStream都有每次只对一个字节数据进行操作的方法也有每次对一批数据进行操作的方法(C#缺乏一次对一个字节数组操作的能力只能通过偏移量/长度参数对字节数组进行操作)
表Java和C#中的同步I/O操作
Java编程人员需要注意的一点是不要忘记IOException与Java不同C#编译器在编译时不要求处理异常情况
Java缺乏完成异步I/O操作的正式方法它没有内置的方法对流进行读写然后再检查其结果其中最相似的一种模拟是在同步操作时产生一个javalangThread线程使得该线程引起侧放作用(某些指令取出后暂时不执行放在一边)或完成检查工作C#的库中有内置的异步I/O操作命令
例如要在Java中执行一个可以对状态进行检查的异步read( byte[] b )操作下面是一种可能的实现方法
file:// 保存读操作的侧放作用的变量
int read; file:// 保存read的结果
IOException exception; // 保存可能发生的异常
Object wait
// 在检查结束前需要保留的一些值
file://InputStream变量is中有关read的封装
( new Thread( new Runnable() {
public void run() {
try {
read isread();
} catch( IOException error ) {
exception error;
} finally {
synchronized( wait ) {
file:// 唤醒等待这一变量的其他进程
// 执行read操作
waitnotifyAll();
}
// 调用检查方法
callback();
}
}
} ) )start();
这将使得read的值或执行读操作的异常情况被分别存储在read和exception中另一个依赖于变量wait的进程可能继续等待或完成检查的方法
C#提供了封装了上述全部功能的BeginRead和EndRead这二个方法BeginRead的作用与Read类似但它对二个或更多的变量━━一个AsyncCallback变量和一个状态对象进行操作返回一个可以稍后用来检查异步读进程的IAsyncResult对象标准的BeginRead的用法与下面的用法相似
IAsyncResult iar sbsBeginRead( buffer
new AsyncCallback( = callback ) null );
带callback方法的用法如下
public void callback( IAsyncResult iar )
要检查实际读取了多少字节可以调用带IAsyncResult对象参数的EndRead方法需要记住的是在BeginRead执行完毕之前EndRead的调用将被阻塞要在没有阻塞的情况下检查read的状态可以检查返回的IAsyncResult变量的IsCompleted属性另外需要注意的是在异步read完成之前缓沖区中的内容是不可靠的
实现流操作
Java和C#中的流数据非常地相似如果对Java中的流操作足够熟悉在C#中完成流操作就不会是太困难的事儿了Java和C#中实现流操作的最主要的差别不仅仅是需要实现的适当的读或写方法还有C#中的Stream类还可以作为读者或作者和准确反映Stream容量的属性
表Java和C#中Stream操作的实现
C#中的Stream类在完成某一种功能时提供了多种选择最重要的Read和Write(二者都需要一个字节数组偏移量长度三个参数)这二个方法就足够了因为所有方法的执行都会用到其他的方法简单的read/write方法将能够给流添加所需要的功能缺省的ReadByte和WriteByte的执行方式将把long型变量与字节数组之间进行转换异步执行的BeginRead和BeginWrite方法将在独立的线程中执行Read或Write方法
这篇稿子的大部分篇幅谈论的都是C#中的SystemIOStream类有关在这里我们还需要讨论一下SystemIOTextReader和SystemIOTextWriter这二个类这二个类与Java处理I/O的方式十分相似其中的一个类负责处理读取操作另一个类则负责处理写操作C#中的Stream对象掩盖了如何读取写的有关细节TextReader和TextWriter则分别独立地存储着读取或写入的字节由上述二种类衍生出的最通用的类是SystemIOStreamReader和SystemIOStreamWrtiter类这二个类都可以对一个Stream对象进行操作SystemTextEncoding对象指定一个字节流如何转换为字符流(缺省情况下C#使用UTF进行编码/解码)
如果需要使用与流类似的功能而且需要对字符而不是字节进行操作使用TextReader和TextWriter二个类的子类要比使用Stream类简单得多虽然如果Stream动用得当也可以使用StreamReader和StreamWriter类实现流操作
文件系统I/O
在Java中完成磁盘操作是十分简单的通常情况下它就是操作javaioFile对象和使用javaioFileInputStream或javaioFileOutputStream跟我们在上面看到的一样C#在许多方面与Java相同但也有一些不同之处
与Java一样C#的文件对象与底层的文件系统之间并没有特别紧密的联系我们可以为一个不存在的文件创建一个File对象也可以为存在的文件创建一个File对象并在C#不知道的情况下将它移到别处由于拥有CreateText或AppendText等向文件系统返回一个流的静态方法因此与Java不同的是C#中的File对象的作用要重要得多
在Java中要创建一个新文件或向文件写内容则必须使用FileInputStream
FileOutputStream fos = new FileOutputStream( brandnewfiletxt);
foswrite( )
但在C#中就可以使用
Stream s = FileCreate( brandnewfiletxt );
或者使用
StreamWriter sw = FileCreateText( brandnewfiletxt );
来得到一个新文件的Stream或StreamWriter(Java中的添加可以通过设置FileOutputStream的构建者之一的append属性来完成)Java允许使用javaioFileInputStream从文件中读取内容而C#则有Open Write和OpenText等静态的方法最后C#在Open方法中提供了更详细的控制━━这一方法允许设置文件的权限和访问环境
表操作文件读写的方法
C#中值得一提的改进是FileCopy方法困扰大多数Java编程人员的一个与文件系统I/O有关的问题是不能正确地移动文件javaioFile中包含一个可以对文件重新命名的renameTo方法但它只在文件系统内有效大多数情况下编程人员都必须编写自己的文件移动命令一般是利用javaioFileInputStream和javaioFileOutputStream拷贝文件然后再删除原来的文件C#中的Copy方法可以很方便地移动文件但FileMove也不能跨卷和文件系统移动文件
C#的文件系统无须处理Java必须处理的跨平台问题因此也就没有与javaioFilepathSeparator或javaioFileseparator功能类似的对象不幸的是这也就意味着在C#中不存在受到广大编程人员喜爱的javaioFile构造器
public File( File parent String child )
使用C#的编程人员可以使用下面的命令来构造一个新的SystemIOFile对象
File parent
File child new File( parentFullName + \\ + childName );
Understanding Networking
二种语言都围绕着基本协议提供了一些抽象层Java中的Socket类的抽象程度要远高于C#中的SystemNetSocketsSocket类
Java和C#都提供了对网络的不同抽象层编程人员可以使用不同的网络接口完成对网络的操作
表Java和C#中的网络层次
应答/请求层可以用于HTTP类的请求其中的一端开始启动一个连接发送一些字节的数据然后停止等待对方作为应答发回的一些字节对于象流这样更灵活的操作协议层的用处更大对于大多数的Java编程人员来说除非需要完成性能非常高的网络操作不需要对套接字进行直接控制如果需要C#仍然提供了对原始的Berkeley套接字进行控制的能力
应答/请求层
这个层次抽象掉了所有网络层的细节提供了一个可以双向传输数据的象流那样的接口Java可以接受HTTP URL并通过下面的命令完成GET命令
URL url= new URL( );
URLConnection urlConnection urlopenConnection();
InputStream input urlConnectiongetI