'Project/Java Network Programming'에 해당되는 글 3건

  1. 2010.12.27 Readers and Writers
  2. 2010.12.27 Encrypting Streams 1
  3. 2010.12.27 Digest Streams
Writers

The Writer class mirrors the java.io.OutputStream class. It's abstract and has two protected constructors.

protected Writer()
protected Writer(Object lock)
public abstract void write(char[] text, int offset, int length) throws IOException
public void write(int c) throws IOException
public void write(char[] text) throws IOException
public void write(String s) throws IOException
public void write(String s, int offset, int length) throws IOException
public abstract void flush() throws IOException
public abstract void close() throws IOException

The write(char[] text, int offset, int length) method is the base method in temrs of which the other four write() methods are implemented. A subclass must override at least this method as well as flush() and close(). LIke OutputStream, the Writer class is never used directly, only polymorphically through one of its subclasses. Writers may be buffered, either directly by being chained to a BufferedWriter or indirectly because their underlying output stream is buffered. To force a write to be committed to the output medium, invoke the flush() method. Once a writer has been closed, further writes will throw IOExceptions.

OutputStreamWriter

OutputStreamWriter is the most important concrete subclass of Writer. An OutputSTreamWriter receives Unicode characters from a Java program. It converts these into bytes according to a specified encoding and writes them onto an underlying output stream. If no encoding is specified, the default encoding for the platform is used. (In the United States, the default encoding is ISO Latin-1 on Solaris and Windows, MacRoman on the Mac.)


Readers

The Reader class mirrors the java.io.InputStream class.

protected Reader()
protected Reader(Object lock)
public abstract int read(char[] text, int offset, int length) throws IOException
public int read() throws IOException
public int read(char[] text) throws IOException
public long skip(long n) throws IOException
public boolean ready()
public boolean markSupported()
public void mark(int readAheadLimit) throws IOException
public void reset() throws IOException
public abstract void close() throws IOException

Like InputStream and Writer, the Reader class is never used directly, only polymorphically through one of its subclasses. The read() method returns a single Unicode character as an int with a value from 0 to 65,535 or -1 on end of stream. The skip(long n) method skips n characters. The mark() and reset() methods allow some readers to reset back to a marked position in the character sequence. The markSupported() method tells you whether this reader supports marking and resetting. The close() method closes the reader and any underlying input stream so that further attempts to read from it will throw IOException.

InputStreamReader is the most important concrete subclass of Reader. An InputStreamReader reads bytes from an underlying input stream such as a FileInputStream or TelnetInputStream. It converts these into characters according to a specified encoding and returns them.


Buffered readers and writers

The BufferedReader and BufferedWriter classes are the character-based equivalents of the byte-oriented BufferedInputStream and BufferedOutputStream classes. Where BufferedInputStream and BufferedOutputStream use an internal array of bytes as a buffer, BufferedReader and BufferedWriter use an internal array of chars.

When a program reads from a BufferedReader, text is taken from the buffer rather than directly from the underlying input stream or other text source. When the buffer empties, it is filled again with as much text as possible, even if not all of it is immediately needed. This will make future reads much faster.

When a program writes to a BufferedWriter, the text is placed in the buffer. The text is moved to the underlying output stream or other target only when the buffer fills up or when the writer is explicitly flushed. This can make writes much faster than would otherwise be the case.

public BufferedReader(Reader in, int buffersize)
public BufferedReader(Reader in)
public BufferedWriter(Writer out)
public BufferedWriter(Writer out, int buffersize)

Both BufferedReader and BufferedWriter have the usual methods associated with readers and writers, like read(), ready(), write(), and close(). They each have two constructors used to chain the BufferedReader or BufferedWriter to an underlying reader or writer and to set the size of the buffer. If the size is not set, then the default size of 8,192 characters is used.


PrintWriter

The PrintWriter class is a replacement for Java 1.0's PrintStream class that properly handles multibyte character sets and international text. Most of these methods behave the same for PrintWriter as they do for PrintStream. The exceptions are that the four write() methods write characters rather than bytes and that if the underlying writer properly handles character set conversion, then so do all the methods of the PrintWriter. This is an improvement over the noninternationalizable PrintStream class, but it's still not good enough for network programming. PrintWriter still has the problems of platform dependency and minimal error reporting that plague PrintStream.
Posted by Triton
,
For legal reasons, the filters for encrypting and decrypting data, CipherInputStream and CipherOutputStream, are part of a standard extension to Java called the Java Cryptography Extension, JCE for short.

The CipherInputStream and CipherOutputStream classes are both powered by a Cipher engine object that encapsulates the algorithm used to perform encryption and decryption. By changing the Cipher engine object, you change the algorithm that the streams use to encrypt and decrypt. Symmetric or secret key ciphers use the same key for both encryption and decryption. Asymmetric or public key ciphers use the different keys for encryption and decryption. The encryption key can be distributed as long as the decryption key is kept secret. Keys are specific to the algorithm in use, and are represented in Java by instances o the java.security.Key interface. The Cipher object is set in the constructor. Like all filter stream constructions, these constructors also take another input stream as an argument.

package javaio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Provider;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public class EncryptingStreams {
public static String infile = "secrets.txt";
public static String outfile = "secrets.des";
public static String password = "Mary had a little spider";
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
FileInputStream fin = new FileInputStream(infile);
FileOutputStream fout = new FileOutputStream(outfile);
//register the provider that implements the algorithm
Provider sunJce = new com.sun.crypto.provider.SunJCE();
Security.addProvider(sunJce);
// create a key
char[] pbeKeyData = password.toCharArray();
PBEKeySpec pbeKeySpec = new PBEKeySpec(pbeKeyData);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
// use Data ENcryption Standard
Cipher pbe = Cipher.getInstance("PBEWithMD5AndDES");
pbe.init(Cipher.ENCRYPT_MODE, pbeKey);
CipherOutputStream cout = new CipherOutputStream(fout, pbe);
byte[] input = new byte[64];
while(true){
int bytesRead = fin.read(input);
if(bytesRead==-1) break;
cout.write(input, 0, bytesRead);
}
cout.flush();
cout.close();
fin.close();
}
catch(Exception e){
System.err.println(e);
e.printStackTrace();
}
}

}


Posted by Triton
,
The java.util.security package contains two filter streams that can calculate a message digest for a stream. They are DigestInputStream and DigestOutputStream. A message digest, represented in Java by the java.util.security.MessageDigest class, is a strong hash code for the stream. Message digests can be used for digital signatures and for detecting data that has been corrupted in transit across the network.

In practice, the use of message digests in digital signatures is more important. Mere data corruption can be detected with much simpler, less computationally expensive algorithms. However, the digest filter streams are so easy to use that at times it may be worth paying the computational price for the corresponding increase in programmer productivity.

MessageDigest sha = MessageDigest.getInstance("SHA");  // Construct a MessageDigest object that uses a particular algorighm, such as the Secure Hash Algorith (SHA). 
DigestOutputStream dout = new DigestOutputStream(out, sha); //Pass both the MessageDigest object and the stream you want to digest to the DigestOutputStream constructor. This chains the digest stream to the underlying output stream. 
byte[] buffer = new byte[128];
while (true){
int bytesRead = in.read(buffer);
if (bytesRead < 0 ) break;
dout.write(buffer, 0, bytesRead);
}
dout.flush();
dout.close();
byte[]result = dout.getMessageDigest().digest(); // Invoke the getMessageDigest() method to retrieve the MessageDigest object. Finally you invoke the digest() method on the MessageDigest object to finish calculating the actual digest.

Calculating the digest of an input stream you read is equally simple. It still isn't quite as transparent as some of the other filter streams because you do need to be at least marginally conversant with the methods of the MessageDigest class. Nonetheless, it's still far easier than writing your own secure hash function and manually feeding it each byte you write.

Posted by Triton
,