C# I/O and Networking
Pages: 1, 2
Filesystem I/O
Performing disk operations in Java is pretty simple -- it mostly involves manipulating the java.io.File object and using either a java.io.FileInputStream or a java.io.FileOutputStream. As we have seen many times before, C# is like Java but slightly different.
Like Java, C# File objects do not have a concrete tie to the underlying filesystem; it is possible to create File objects for non-existent files, and it is also possible create a File for an existing file and move that file out from underneath the CLR without the C# program noticing until it attempts to open the file. Unlike Java, the File object can play a much more pivotal role as it has static methods such as CreateText or AppendText that will return a stream to the filesystem. In Java, the constructor for the FileInputStream must be used to get the same functionality.
To create a new file for writing to in Java, you just have to use the FileInputStream to
FileOutputStream fos new FileOutputStream( "brand-new-file.txt" =);
fos.write( ... )
but C# allows either a
Stream s File.Create( "brand-new-file.txt" );
or a
StreamWriter sw File.CreateText( "brand-new-file.txt" );
to get a Stream or a StreamWriter to the new file. (Appending in Java is done by setting the "append" boolean in one of the FileOutputStream's constructors.) Java allows for reading from files using the java.io.FileInputStream, while C# has static methods named Open Write and OpenText. Lastly, C# offers more fine-grained control in its Open method -- this method exposes the ability to set the file permissions and access contexts.
Table 3: Manipulating files for reading and writing | ||
Function |
Java |
C# |
Create a new file for writing |
Use the |
Either use the static |
Write to an existing file |
Use the |
Use either the static or instance |
Append text to a file |
Use the |
Use either the static or instance |
Read text from a file |
Use the |
Make use of the static or instance |
Another improvement that C# has made that is worth mentioning for curiosity's sake is the inclusion of a File.Copy method. A problem that most Java programmers who have worked with filesystem I/O notice is the inability to properly move files. java.io.File contains a renameTo method that can rename a file; however, that does not work over filesystem boundaries (disks, networks, etc.). Most of the time, programmers are forced to implement their own move command, which copies the file using both a java.io.FileInputStream and a java.io.FileOutputStream, then deletes the original file. C#'s inclusion of a Copy method makes moving files trivial, though the File.Move command also does not work across volumes and filesystem boundaries.
The C# file-system implementation does not have to deal with the cross-platform issues that the Java model has to cope with. There are no equivalent variables to the java.io.File.pathSeparator or the java.io.File.separator. Unfortunately, this also means that the favorite of the java.io.File constructors
public File( File parent, String child )
does not exist -- instead, C# programmers are left with constructing a new System.IO.File object with
File parent ...
File child new File( parent.FullName + "\\" + childName );
Understanding Networking
Both programming languages provide a few layers of abstraction around a base level socket implementation -- granted, Java's java.net.Socket class is far more abstract than C#'s System.Net.Sockets.Socket class.
Table 4: Network architecture tiers in Java and C# | ||
Tier |
Java |
C# |
Response/Request |
|
|
Protocol |
|
|
Raw Socket |
N/A |
|
The Response/Request tier can be used for HTTP type requests, where one end initiates a connection, sends bytes down the stream, and then blocks while it waits for a set of bytes as a response. For more fluid stream-like operations, the protocol tier can be very useful (we will cover TCP/IP operations below). Most Java programmers, unless highly optimizing network operations, do not require fine socket control -- C# still does provide the ability to control raw Berkeley sockets if it is needed.
Response/Request Tier
This tier heavily abstracts away all the networking and provides a stream-like interface to move data back and forth. Java will take a HTTP URL and perform a GET simply by doing a
URL url new URL( "http://to.post.to.com" );
URLConnection urlConnection url.openConnection();
InputStream input urlConnection.getInputStream();
... read stuff from input ...
input.close();
C# mimics this code with its System.Net.WebRequest object:
WebRequest request WebRequestFactory.Create( =
"http://to.post.to.com" );
Stream input request.GetResponse().GetResponseStream();
... read stuff from input ...
input.Close();
Both of these implementations will hide the underlying socket creation and HTTP protocol requirements and will simply provide streams that the programmer can use to ship and then receive data. Just like the C# Stream class, the WebRequest class has methods to asynchronously get a request stream to write to or a WebResponse object to read from.
Protocol Tier
The System.Net.Sockets.TCPClient class should seem very familiar to those Java programmers familiar with java.net.Socket, as they are nearly identical; both share a very similar API and share similar functionality, as the programmer does not have to deal with the socket implementation but instead only the return streams to be used.
A simplistic telnet client implementation can be concocted in Java by simply using:
Socket telnet new Socket( "telnet.host.com", 23 );
OutputStream output telnet.getOutputStream();
InputStream input telnet.getInputStream();
and both streams can be used in conjunction to telnet to telnet.host.com. The same program can be written in C# in almost the same fashion:
TCPClient telnet new TCPClient( "telnet.host.com", 23 );
Stream telnetStream telnet.GetStream();
StreamWriter output new StreamWriter( telnetStream );
StreamReader input new StreamReader( telnetStream );
Also, receiving a TCP/IP connection is nearly identical in both languages, as an incoming socket in Java is set up and then received using:
ServerSocket server new ServerSocket( 23 );
Socket accept server.accept();
while C# allows for:
TCPListener server new TCPListener( 23 );
server.Start();
Socket accept server.Accept();
In both languages, each socket that is accepted needs to be dealt with separately. In Java, the preferred way (until Java 1.4) is to spawn a thread for each individual socket that is received. The same can be done for the C# sockets; however, the Socket class provides the ability to use an event-driven interface with the "select" method. (Programming sockets in an event-driven model is outside the scope of this article.)
Raw Socket Tier
Here, we probably venture into unfamiliar territory for most Java programmers. Java-only programmers rarely need to know anything about the Berkeley socket implementation, as it is being abstracted away by the java.net.Socket and java.net.DatagramSocket classes. By manipulating this Berkeley socket class properly, the familiar Java functionality of streams can be achieved.
Now we have a C# repertoire that includes the most powerful abstractions from Java -- the ability to perform I/O and networking. Check back for the next article in this series, which will cover multi-threading to allow for parallel operations.
Raffi Krikorian makes a career of hacking everything and anything. Professionally, he is the founding partner at Synthesis Studios: a technological design and consulting firm that orchestrates his disjointed train of thought.
Return to ONJava.com.
-
High performance C# server
2008-04-17 13:52:58 TomGibbson [View]
-
OS Async I/O or Thread base Simulation?? - Clarification
2003-05-20 02:21:45 anonymous2 [View]
-
OS Async I/O or Thread base Simulation??
2003-05-20 02:10:25 anonymous2 [View]
-
Nice Article
2003-02-20 12:25:01 anonymous2 [View]
-
Asynchronous IO available in JAVA
2001-12-20 06:20:07 regis21 [View]

