Siêu thị PDFTải ngay đi em, trời tối mất

Thư viện tri thức trực tuyến

Kho tài liệu với 50,000+ tài liệu học thuật

© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

Thinking in C# phần 7 pptx
MIỄN PHÍ
Số trang
80
Kích thước
605.6 KB
Định dạng
PDF
Lượt xem
1743

Thinking in C# phần 7 pptx

Nội dung xem thử

Mô tả chi tiết

494 Thinking in C# www.ThinkingIn.NET

Random access with Seek

The Stream base class contains a method called Seek( ) that can be used to jump

between records and data sections of known size (or sizes that can be computed

by reading header data in the stream). The records don’t have to be the same size;

you just have to be able to determine how big they are and where they are placed

in the file. The Seek() method takes a long (implying a maximum file size of 8

exabytes, which will hopefully suffice for a few years) and a value from the

SeekOrigin enumeration which can be Begin, Current, or End. The

SeekOrigin value specifies the point from which the seek jumps.

Although Seek( ) is defined in Stream, not all Streams support it (for instance,

one can’t “jump around” a network stream). The CanSeek bool property

specifies whether the stream supports Seek( ) and the related Length( ) and

SetLength( ) mehods, as well as the Position( ) method which returns the

current position in the Stream. If CanSeek is false and one of these methods is

called, it will throw a NotSupportedException. This is poor design. Support

for random access is based on type, not state, and should be specified in an

interface (say, ISeekable) that is implemented by the appropriate subtypes of

Stream.

If you use SeekOrigin.End, you should use a negative number for the offset;

performing a Seek( ) beyond the end of the stream moves to the end of the file

(i.e., ReadByte( ) will return a -1, etc.).

This example shows the basic use of Stream.Seek( ):

//:c12:FibSeek.cs

using System;

using System.IO;

class FibSeek {

Stream src;

FibSeek(Stream src){

this.src = src;

}

void DoSeek(SeekOrigin so){

if (so == SeekOrigin.End) {

src.Seek(-10, so);

} else {

Chapter 12: I/O in C# 495

src.Seek(10, so);

}

int i = src.ReadByte();

Console.WriteLine(

"10 bytes from {0} is : {1}", so, (char) i);

}

public static void Main(string[] args){

foreach(string fName in args){

FileStream f = null;

try {

f = new FileStream(fName, FileMode.Open);

FibSeek fs = new FibSeek(f);

fs.DoSeek(SeekOrigin.Begin);

fs.DoSeek(SeekOrigin.End);

f.Seek(12, SeekOrigin.Begin);

fs.DoSeek(SeekOrigin.Current);

} catch (Exception ex) {

Console.WriteLine(ex);

} finally {

f.Close();

}

}

}

}///:~

Standard I/O

The term standard I/O refers to the Unix concept (which is reproduced in some

form in Windows and many other operating systems) of a single stream of

information that is used by a program. All the program’s input can come from

standard input, all its output can go to standard output, and all of its error

messages can be sent to standard error. The value of standard I/O is that

programs can easily be chained together and one program’s standard output can

become the standard input for another program. More than just a convenience,

this is a powerful architectural pattern called Pipes and Filters; although this

architecture was not very common in the 1990s, it’s a very powerful one, as

anyone who’s witnessed a UNIX guru can testify.

496 Thinking in C# www.MindView.net

Reading from standard input

Following the standard I/O model, the Console class exposes three static

properties: Out, Error, and In. In Chapter 11 we sent some error messages to

Console.Error. Out and Error are TextWriters, while In is a TextReader.

Typically, you either want to read console input as either a character or a

complete line at a time. Here’s an example that simply echoes each line that you

type in:

//:c12:EchoIn.cs

//How to read from standard input.

using System;

public class EchoIn {

public static void Main(){

string s;

while ((s = Console.In.ReadLine()).Length != 0)

Console.WriteLine(s);

// An empty line terminates the program

}

} ///:~

Redirecting standard I/O

The Console class allows you to redirect the standard input, output, and error

I/O streams using simple static method calls:

SetIn(TextReader)

SetOut(TextWriter)

SetError(TextWriter)

(There is no obvious reason why these methods are used rather than allowing the

Properties to be set directly.)

Redirecting output is especially useful if you suddenly start creating a large

amount of output on your screen and it’s scrolling past faster than you can read

it. Redirecting input is valuable for a command-line program in which you want

to test a particular user-input sequence repeatedly. Here’s a simple example that

shows the use of these methods:

//:c12:Redirecting.cs

// Demonstrates standard I/O redirection.

using System;

Chapter 12: I/O in C# 497

using System.IO;

public class Redirecting {

public static void Main(){

StreamReader sr = new StreamReader(

new BufferedStream(

new FileStream(

"Redirecting.cs", FileMode.Open)));

StreamWriter sw = new StreamWriter(

new BufferedStream(

new FileStream(

"redirect.dat", FileMode.Create)));

Console.SetIn(sr);

Console.SetOut(sw);

Console.SetError(sw);

String s;

while ((s = Console.In.ReadLine()) != null)

Console.Out.WriteLine(s);

Console.Out.Close(); // Remember this!

}

} ///:~

This program attaches standard input to a file, and redirects standard output and

standard error to another file.

Debugging and Tracing

We briefly discussed the Debug and Trace classes of the System.Diagnostics

namespace in chapter 6. These classes are enabled by conditionally defining the

values DEBUG and TRACE either at the command-line or in code. These

classes write their output to a set of TraceListener classes. The default

TraceListener of the Debug class interacts with the active debugger, that of

the Trace class sends data to the console. Customizing both is easy; the

TextWriterTestListener decorates any TextWriter with TestListener

capabilities. Additionally, EventLogTraceListener ; sending data to the

console or the system’s event logs takes just a few lines of code:

//:c12:DebugAndTrace.cs

//Demonstates Debug and Trace classes

#define DEBUG

#define TRACE

498 Thinking in C# www.ThinkingIn.NET

using System;

using System.Diagnostics;

class DebugAndTrace {

public static void Main(){

TextWriterTraceListener conWriter =

new TextWriterTraceListener(Console.Out);

Debug.Listeners.Add(conWriter);

Debug.WriteLine("Debug to stdout");

EventLogTraceListener logWriter =

new EventLogTraceListener("DebugTraceProg");

Trace.Listeners.Add(logWriter);

Debug.Listeners.Add(logWriter);

Trace.WriteLine("Traced");

Debug.WriteLine("Debug trace");

logWriter.Close();

}

}///:~

When run, both Debug and Trace are written to the console. In addition, an

EventLogTraceListener object whose Source property is set to

“DebugTraceLog.” This value is used to show in the system’s event logs the source

of trace information:

Chapter 12: I/O in C# 499

Figure 12-2: Using the system Event Viewer to see program output

If you wish to create your own event log, that’s easy, too:

EventLog log = new EventLog("MySecond.log");

log.Source = "DebugAndTraceProgram";

EventLogTraceListener logWriter =

new EventLogTraceListener(log);

I think this section could be expanded a bit.

Regular expressions

Regular expressions are a powerful pattern-matching tool for interpreting and

manipulating strings. Although regular expressions are not necessarily related to

input and output, it is probably their most common application, so we’ll discuss

them here.

Regular expressions have a long history in the field of computer science but

continue to be expanded and improved, which gives rise to an intimidating set of

capabilities and alternate routes to a given end. The regular expressions in the

.NET Framework are Perl 5 compatible but include additional features such as

right-to-left matching and do not require a separate compilation step.

The fundamental responsibility of the System.Text.RegularExpressions

Regex class is to match a given pattern with a given target string. The pattern is

described in a terse notation that combines literal text that must appear in the

500 Thinking in C# www.MindView.net

target with meta-text that specifies both acceptable variations in text and desired

manipulations such as variable assignment or text replacement.

This sample prints out the file names and lines that match a regular expression

typed in the command line:

//:c12:TGrep.cs

//Demonstrate basic regex matching against files

using System;

using System.IO;

using System.Text.RegularExpressions;

class TGrep {

public static void Main(string[] args){

TGrep tg = new TGrep(args[0]);

tg.ApplyToFiles(args[1]);

}

Regex re;

TGrep(string pattern){

re = new Regex(pattern);

}

void ApplyToFiles(string fPattern){

string[] fNames =

Directory.GetFiles(".", fPattern);

foreach (string fName in fNames ) {

StreamReader sr = null;

try {

sr = new StreamReader(

new BufferedStream(

new FileStream(

fName, FileMode.Open)));

string line = "";

int lCount = 0;

while ((line = sr.ReadLine()) != null) {

lCount++;

if (re.IsMatch(line)) {

Console.WriteLine(

"{0} {1}: {2}", fName, lCount, line);

}

}

Chapter 12: I/O in C# 501

} finally {

sr.Close();

}

}

}

}///:~

The Main( ) method passes the first command-line argument to the TGrep( )

constructor, which in turn passes it to the Regex( ) constructor. The second

argument is then passed as the argument to the ApplyToFiles( ) method.

ApplyToFiles( ) uses IO techniques we’ve discussed previously to read a series

of files line-by-line and incrementing the variable lCount to let us know what

line number works. Each line is passed to the Regex.IsMatch( ) method, and if

that method returns true, the filename, line number, and contents of the line are

printed to the screen.

You might guess that “tgrep using tgrep.cs” would print lines 3, 4, and 5 of

tgrep.cs, but you might not expect that “tgrep [0-9] tgrep.cs” would print every

line that contains a number, or that “tgrep [\s]f[\w]*[\s]*= *.cs” would print

every line that assigns a value to a variable that begins with a lowercase “f”. Like

SQL in ADO.NET, the regular expression notation is a separate language quite

unlike C#, and Thinking in Regular Expressions would be quite a different book

than this one.

In addition to simply determining if a match exists, Regex can actually return

the value of the matches, as this program demonstrates:

//:c12:GrepMatches.cs

using System;

using System.IO;

using System.Text.RegularExpressions;

class GrepMatches {

public static void Main(string[] args){

GrepMatches tg = new GrepMatches(args[0]);

string target = args[1];

tg.ApplyToFiles(target);

}

Regex re;

GrepMatches(string pattern){

re = new Regex(pattern);

Tải ngay đi em, còn do dự, trời tối mất!