1. Trang chủ
  2. » Công Nghệ Thông Tin

Thinking in C# phần 7 pptx

80 252 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 80
Dung lượng 605,55 KB

Nội dung

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); 502 Thinking in C# www.ThinkingIn.NET } 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); ShowMatches(re.Matches(line)); } } } finally { sr.Close(); } } } private void ShowMatches(MatchCollection mc){ for (int i = 0; i < mc.Count; i++) { Console.WriteLine( "Match[{0}] = {1}", i, mc[i]); } } }///:~ Regex.Matches( ) returns a MatchCollection which naturally contains Match objects. This sample program can be helpful in debugging the development of a regular expression, which for most of us requires a considerable amount of trial and error! Chapter 12: I/O in C# 503 The static method Regex.Replace() can make complex transformations surprisingly straightforward. This sample makes pattern substitutions in a text file: //:c12:TSed.cs using System; using System.IO; using System.Text.RegularExpressions; class TSed { public static void Main(string[] args){ TSed tg = new TSed(args[0], args[1]); string target = args[2]; tg.ApplyToFiles(target); } string pattern; string rep; TSed(string pattern, string rep){ this.pattern = pattern; this.rep = rep; } 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) { string nLine = Regex.Replace(line, pattern, rep); Console.WriteLine(nLine); } } finally { [...]... = ""; int lCount = 0; while ((line = fStream.ReadLine()) != null) { lCount++; if (Suspicious(line)) { Console.WriteLine( "{0}: {1}", lCount, line); } } } bool Suspicious(string line){ if (MatchNotKeyword(line, blockPrefix) == true) { return true; } if (MatchNotKeyword(line, methodDef) == true) { return true; } 506 Thinking in C# www.ThinkingIn.NET return false; } bool MatchNotKeyword(string line, Regex... Type (described previously in this chapter) supports the concept of reflection, and there’s an additional namespace, System.Reflection, with classes EventInfo, FieldInfo, MethodInfo, PropertyInfo, and ConstructorInfo (each of which inherit from MemberInfo) Objects of these 526 Thinking in C# www.ThinkingIn.NET types are created at run-time to represent the corresponding member in the unknown class You... object, a single Type object is created A collection of Type 1 In fact, all your objects will be of type RuntimeType, which is a subtype of Type 514 Thinking in C# www.ThinkingIn.NET objects is stored in binary format in an assembly (usually having an extension of dll or exe) At run-time, when you want to make an object of that type, the CLR first checks to see if the Type has been instantiated within the... (anotherType); Possibly many layers of inheritance AnotherType AnotherType someType.IsSubclassOf (anotherType); Possibly many layers of inheritance SomeType 522 Thinking in C# www.ThinkingIn.NET SomeType someType.IsInstanceOfType (aThirdObject); Possibly many layers of inheritance AThirdType RTTI syntax C# performs its RTTI using the Type object, even if you’re doing something like a cast The class Type also... sometimes marks strings that contain formatting brackets incorrectly If you improve the program, please drop the authors a line at www.ThinkingIn.Net Chapter 12: I/O in C# 5 07 Summary The NET IO stream library does satisfy the basic requirements: you can perform reading and writing with the console, a file, a block of memory, or even across the Internet (as you will see in Chapter 18) With inheritance, you... an invalid target How are target’s specified? Why, with the AttributeUsageAttribute: //:c13:Meaningless2.cs //Compile with csc /target:library Meaningless2.cs //A meaningless attribute using System; 528 Thinking in C# www.MindView.net [AttributeUsage (AttributeTargets.Class)] public class Meaningless : Attribute { public Meaningless(){ Console.WriteLine("Meaningless created"); } }///:~ The Meaningless... of polymorphism and upcasting, you might code the above example as follows: //:c13:Shapes.cs using System; using System.Collections; class Shape { internal void Draw() { Console.WriteLine(this + ".Draw()"); } } class Circle : Shape { 512 Thinking in C# www.MindView.net public override string ToString() { return "Circle";} } class Square : Shape { public override string ToString() { return "Square";}... Activator.CreateInstance(parent); // (*1*) PrintInfo(o.GetType()); } static void PrintInfo(Type t) { Console.WriteLine( "Class name: " + t.FullName + " is interface? [" + t.IsInterface + "]"); } } ///:~ You can see that class FancyToy is quite complicated, since it inherits from Toy and implements the interfaces of HasBatteries, Waterproof, and ShootsThings In Main( ), a Type reference is created and initialized... Type object is Type.GetType( ), which takes a string containing the textual name of the particular class you want a reference for When you run this program, the output will be: Inside Main Candy loaded After creating Candy After Type.GetType("Gum") Gum loaded juicyfruit 516 Thinking in C# www.MindView.net Before creating Cookie Cookie loaded After creating Cookie You can see that each Class object is... class that’s being created with CreateInstance( ) must have a default constructor In the next section, you’ll see how to dynamically create objects of classes using any constructor, with the C# reflection API The final method in the listing is PrintInfo( ), which takes a Type reference and gets its name, including its namespace, from its FullName property and whether it’s an interface with IsInterface The . 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;. marks strings that contain formatting brackets incorrectly. If you improve the program, please drop the authors a line at www.ThinkingIn.Net. 508 Thinking in C# www.MindView.net Summary The. Regex re; GrepMatches(string pattern){ re = new Regex(pattern); 502 Thinking in C# www.ThinkingIn.NET } void ApplyToFiles(string fPattern){ string[] fNames = Directory.GetFiles(

Ngày đăng: 06/08/2014, 20:20