Skip to content

Commit f867a1d

Browse files
Refactor with interface
Synchronous methods are faster
1 parent 8e639dd commit f867a1d

File tree

6 files changed

+114
-122
lines changed

6 files changed

+114
-122
lines changed

TextFileConvert/Common.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
using System;
22
using System.IO;
33
using System.Text;
4-
using System.Threading.Tasks;
54

65
namespace TextFileConvert;
76

87
public static class Common
98
{
9+
public const byte Cr = 13; //'\r'; // Carriage Return
10+
public const byte Lf = 10; //'\n'; // Line Feed
11+
1012
/// <summary>
1113
/// This is the command line help that is displayed when invalid parameters are given.
1214
/// </summary>
@@ -32,10 +34,11 @@ public static void PrintUsage(string programName)
3234
/// </summary>
3335
/// <param name="theFile">The file to get the encoding pattern from.</param>
3436
/// <returns>Encoding type, defaults to ASCII.</returns>
35-
public static async Task<Encoding> GetEncoding(FileStream theFile)
37+
[Obsolete("No longer used internally. Prefer native methods.")]
38+
public static Encoding GetEncoding(FileStream theFile)
3639
{
3740
var bom = new byte[4];
38-
var count = await theFile.ReadAsync(bom, 0, 4);
41+
var count = theFile.Read(bom, 0, 4);
3942

4043
// Detect BOM type
4144
if (count > 2 && bom[0] == 0x2B && bom[1] == 0x2F && bom[2] == 0x76)
Lines changed: 10 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,12 @@
11
using System;
2-
using System.Diagnostics;
32
using System.IO;
43
using System.Threading.Tasks;
4+
using TextFileConvert.Converters;
55

66
namespace TextFileConvert;
77

88
public class ConvertLineEndings
99
{
10-
private const byte Cr = 13; //'\r'; // Carriage Return
11-
private const byte Lf = 10; //'\n'; // Line Feed
12-
13-
/// <summary>
14-
/// These are the different conversions that this library can perform.
15-
/// </summary>
16-
private enum TextConvertMode
17-
{
18-
Dos2Ux,
19-
Ux2Dos
20-
// Dos2Mac
21-
// Mac2Dos
22-
// Mac2Ux
23-
// Ux2Mac
24-
}
25-
2610
/// <summary>
2711
/// Converts a DOS text file to have Unix line endings.
2812
/// </summary>
@@ -31,7 +15,7 @@ private enum TextConvertMode
3115
/// <returns>Exit code.</returns>
3216
public static async Task<int> Dos2Ux(string originalFile, string newFile)
3317
{
34-
return await ReplaceLineEndings(originalFile, newFile, TextConvertMode.Dos2Ux);
18+
return await ReplaceLineEndings(originalFile, newFile, new ConvertDos2Ux());
3519
}
3620

3721
/// <summary>
@@ -42,7 +26,7 @@ public static async Task<int> Dos2Ux(string originalFile, string newFile)
4226
/// <returns>Exit code.</returns>
4327
public static async Task<int> Ux2Dos(string originalFile, string newFile)
4428
{
45-
return await ReplaceLineEndings(originalFile, newFile, TextConvertMode.Ux2Dos);
29+
return await ReplaceLineEndings(originalFile, newFile, new ConvertUx2Dos());
4630
}
4731

4832
/// <summary>
@@ -52,7 +36,7 @@ public static async Task<int> Ux2Dos(string originalFile, string newFile)
5236
/// <param name="newFile">The name of a new file to create.</param>
5337
/// <param name="convertMode">This is the type of conversion we are going to perform.</param>
5438
/// <returns>Exit code. 0 is success. -1 is a symbolic link.</returns>
55-
private static async Task<int> ReplaceLineEndings(string originalFile, string newFile, TextConvertMode convertMode)
39+
private static async Task<int> ReplaceLineEndings(string originalFile, string newFile, ITextConverter convertMode)
5640
{
5741
try
5842
{
@@ -61,113 +45,20 @@ private static async Task<int> ReplaceLineEndings(string originalFile, string ne
6145
return -1;
6246

6347
using var oldFileStream = new FileStream(originalFile, FileMode.Open, FileAccess.Read, FileShare.Read, 65536, FileOptions.Asynchronous);
64-
65-
// Attempt to detect encoding we will use for reading and writing
66-
var fileEncoding = await Common.GetEncoding(oldFileStream);
67-
Debug.Print(fileEncoding.ToString());
68-
69-
// Rewind stream
70-
oldFileStream.Position = 0L;
71-
await oldFileStream.FlushAsync();
48+
using var newFileStream = new FileStream(newFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 65536, FileOptions.Asynchronous);
7249

7350
// Reading and writing is done in this one line
74-
await WriteConvertedText(oldFileStream, convertMode, newFile);
51+
convertMode.WriteConvertedText(oldFileStream, newFileStream);
52+
await oldFileStream.FlushAsync();
53+
await newFileStream.FlushAsync();
7554
}
7655
catch (Exception ex)
7756
{
78-
Debug.Print("Error: " + ex.Message + Environment.NewLine + "Number: " + ex.HResult.ToString());
57+
Console.WriteLine($"Error: {ex.Message}");
58+
Console.WriteLine($"Number: {ex.HResult}");
7959
return ex.HResult;
8060
}
8161

8262
return 0;
8363
}
84-
85-
/// <summary>
86-
/// This is where the actual conversion logic lives.
87-
/// </summary>
88-
/// <param name="originalFile">The file you want to convert.</param>
89-
/// <param name="convertMode">The type of conversion you want to perform.</param>
90-
/// <param name="newFile">Full path to the new file to write</param>
91-
/// <returns>The full text of the file with new line endings.</returns>
92-
private static async Task WriteConvertedText(FileStream originalFile, TextConvertMode convertMode, string newFile)
93-
{
94-
//using var oldFile = new StreamReader(originalFile, fileEncoding, true);
95-
using var newFileStream = new FileStream(newFile, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 65536, FileOptions.Asynchronous);
96-
switch (convertMode)
97-
{
98-
case TextConvertMode.Dos2Ux:
99-
{
100-
while (originalFile.CanRead)
101-
{
102-
var readBuffer = new byte[1];
103-
int readChars = await originalFile.ReadAsync(readBuffer, 0, 1);
104-
if (readChars == 0) break;
105-
106-
// Look for Dos line endings
107-
if (readBuffer[0] == Cr)
108-
{
109-
// Strip out CR chars if followed by LF
110-
var peekBuffer = new byte[1];
111-
readChars = await originalFile.ReadAsync(peekBuffer, 0, 1);
112-
if (readChars == 0) break;
113-
114-
if (peekBuffer[0] != Lf)
115-
{
116-
originalFile.Position -= 1;
117-
}
118-
else
119-
{
120-
readBuffer = peekBuffer;
121-
}
122-
}
123-
124-
await newFileStream.WriteAsync(readBuffer, 0, 1);
125-
}
126-
127-
break;
128-
}
129-
case TextConvertMode.Ux2Dos:
130-
{
131-
while (originalFile.CanRead)
132-
{
133-
var readBuffer = new byte[1];
134-
int readChars = await originalFile.ReadAsync(readBuffer, 0, 1);
135-
if (readChars == 0) break;
136-
137-
// Check for CR first to avoid doubling the CR character when LF is found
138-
if (readBuffer[0] == Cr)
139-
{
140-
var peekBuffer = new byte[1];
141-
readChars = await originalFile.ReadAsync(peekBuffer, 0, 1);
142-
if (readChars == 0) break;
143-
144-
if (peekBuffer[0] == Lf)
145-
{
146-
// This is a DOS line ending, keep it.
147-
Array.Resize(ref readBuffer, 2);
148-
readBuffer[1] = peekBuffer[0];
149-
}
150-
else
151-
{
152-
// Rewind
153-
newFileStream.Position -= 1;
154-
}
155-
}
156-
else if (readBuffer[0] == Lf)
157-
{
158-
// This is a Unix line ending. Add preceding CR.
159-
readBuffer = new byte[2];
160-
readBuffer[0] = Cr;
161-
readBuffer[1] = Lf;
162-
}
163-
164-
await newFileStream.WriteAsync(readBuffer, 0, readBuffer.Length);
165-
}
166-
167-
break;
168-
}
169-
default:
170-
throw new ArgumentOutOfRangeException(nameof(convertMode), convertMode, "TextConvertMode not yet supported.");
171-
}
172-
}
17364
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.IO;
2+
3+
namespace TextFileConvert.Converters;
4+
5+
public class ConvertDos2Ux : ITextConverter
6+
{
7+
public void WriteConvertedText(FileStream originalFile, FileStream newFile)
8+
{
9+
var readBuffer = new byte[1];
10+
while (originalFile.CanRead)
11+
{
12+
int readChars = originalFile.Read(readBuffer, 0, 1);
13+
if (readChars == 0) break;
14+
15+
// Look for Dos line endings
16+
if (readBuffer[0] == Common.Cr)
17+
{
18+
// Strip out CR chars if followed by LF
19+
var peekBuffer = new byte[1];
20+
readChars = originalFile.Read(peekBuffer, 0, 1);
21+
if (readChars == 0) break;
22+
23+
if (peekBuffer[0] != Common.Lf)
24+
{
25+
originalFile.Position -= 1;
26+
}
27+
else
28+
{
29+
readBuffer = peekBuffer;
30+
}
31+
}
32+
33+
newFile.Write(readBuffer, 0, 1);
34+
}
35+
}
36+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace TextFileConvert.Converters;
5+
6+
public class ConvertUx2Dos : ITextConverter
7+
{
8+
public void WriteConvertedText(FileStream originalFile, FileStream newFile)
9+
{
10+
while (originalFile.CanRead)
11+
{
12+
var readBuffer = new byte[1];
13+
int readChars = originalFile.Read(readBuffer, 0, 1);
14+
if (readChars == 0) break;
15+
16+
// Check for CR first to avoid doubling the CR character when LF is found
17+
if (readBuffer[0] == Common.Cr)
18+
{
19+
var peekBuffer = new byte[1];
20+
readChars = originalFile.Read(peekBuffer, 0, 1);
21+
if (readChars == 0) break;
22+
23+
if (peekBuffer[0] == Common.Lf)
24+
{
25+
// This is a DOS line ending, keep it.
26+
Array.Resize(ref readBuffer, 2);
27+
readBuffer[1] = peekBuffer[0];
28+
}
29+
else
30+
{
31+
// Rewind
32+
originalFile.Position -= 1;
33+
}
34+
}
35+
else if (readBuffer[0] == Common.Lf)
36+
{
37+
// This is a Unix line ending. Add preceding CR.
38+
readBuffer = new byte[2];
39+
readBuffer[0] = Common.Cr;
40+
readBuffer[1] = Common.Lf;
41+
}
42+
43+
newFile.Write(readBuffer, 0, readBuffer.Length);
44+
}
45+
}
46+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.IO;
2+
3+
namespace TextFileConvert.Converters;
4+
5+
public interface ITextConverter
6+
{
7+
/// <summary>
8+
/// This is where the conversion logic lives.
9+
/// </summary>
10+
/// <param name="originalFile">The file to convert.</param>
11+
/// <param name="newFile">The file to write with new line endings</param>
12+
public void WriteConvertedText(FileStream originalFile, FileStream newFile);
13+
}

TextFileConvert/TextFileConvert.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@
2525
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
2626
</None>
2727
</ItemGroup>
28+
<ItemGroup>
29+
<PackageReference Include="System.Memory" Version="4.5.5" />
30+
</ItemGroup>
2831
</Project>

0 commit comments

Comments
 (0)