Passing a Streamwriter as a parameter [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a large file and I am reading each line and depending on what the line contains, I am massaging the line. Here is the code I use when I get to a line that needs to be massaged:
private static void ReviewFile(string fileName, string outFile)
// next initialize StreamReader and read the first line
// depending on the value of that line:
checkFile(out line, ref sw, ref sr); <--- error
Calling:
private void checkFile(out string line, ref StreamWriter sw, ref StreamReader sr)
{
string mVar = line.Trim(); <--- error
sw.WriteLine(mVar);
line = sr.ReadLine();
}
It seems like it should work but I am getting multiple errors. When I call the method, I get "An object reference is required for non-static field" Then within the checkFile method, I get use of unassigned out parameter line. What am I doing wrong? Any help would be graciously appreciated.

In theory, you could simply do the following:
private IEnumerable<string> ReadByLine()
{
string line;
using(StreamReader reader = File.OpenText(FileInformation.FullName))
while((line = reader.ReadLine()) != null)
yield return line;
}
This would allow you to read the file, line by line. Then simply pass the data to another method, to sanitize?
private void Sanitize(IEnumerable<string> document)
{
foreach(var line in document)
{
// Do you check, to sanitize and return or whatever.
}
}
Then you would simply have a two line call in a method:
IEnumerable<string> document = ReadByLine();
Sanitize(document);
This approach would separate the functionality a bit, plus will be easier to follow. Alternative approach to solve your problem. Especially since you approach doesn't seem warranted or viable to enhance the code in anyway.

Based on the code you show, there's absolutely no reason to use ref or out here.
Also, to directly address the issues you ask about, see my comments:
private static void ReviewFile(string fileName, string outFile)
// You're trying to call an instance method from a static method, which doesn't make sense.
// Also, where do you actually declare line, sw, or sr? These are, in fact,
// declared somewhere in this method, right?
checkFile(out line, ref sw, ref sr); <--- error
}
// This is an instance method, NOT a static one
private void checkFile(out string line, ref StreamWriter sw, ref StreamReader sr)
{
// "out" means you intend to initialize "line" in this method before you use it, and you don't.
string mVar = line.Trim(); <--- error
sw.WriteLine(mVar);
// ReadLine doesn't take any arguments
// This should actually be line = sr.ReadLine()
// Also, this should probably go at the beginning of the method
sr.ReadLine(line);
}

Related

Visual Studio issue with recognising variables

Okay so in short:
I declare a variable, say
string str = "Random";
then I try to perform any sort of operation whatsoever, say
str.ToLower();
And neither visual studio, nor intellisense recognise it at all.
VS gives me the name "str" does not exist in the current context. This happened right after I installed xamarin but I'm not sure if it's related.
Also this issue would not occur if I was inside a method, just when I'm directly inside a class.
This is my code:
public class Program {
public void randomMethod() {
string str2 = "Random";
str.ToUpper(); //this line shows no errors
}
string str = "Random";
str.ToLower(); //this line does show the error
}
str would be underlined red and the warning mentioned above would appear.
Does anybody know what's going on?
you even point the issue out yourself
you cannot do this
public class Program {
string str = "Random";
str.ToLower(); //this line does show the error
}
when would you expect that code to run?
You must put executable code inside a function. You point out that this works.
I cannot propose a fix since I do not know what you are trying to do.
It is a scope issue:
public class Program {
public void randomMethod() { //method scope starts
string str2 = "Random";
str.ToUpper(); //this line shows no errors
} //method scope ends
string str = "Random"; //this is a class field, but is missing an accessibility level
str.ToLower(); //this line SHOULD show an error, because you can't do this in a class
}

Which way is better for this method that writes to a file? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
A bit of a silly question but i really cant decide, which was is better?
Either:
// Writes a byte array at offset in file
public void WriteByteArray(string file, long offset, byte[] buffer)
but that will force the user to always write the file path, or have it like this:
private string path;
public string File
{
get { return path; }
set { path = value; }
}
// Will do the same thing as the method above just here,
// except it will use the path which was set via "File"
public void WriteByteArray(long offset, byte[] buffer)
There are pros and cons for both. For the first way the pro is, if you want to write the byte array into different files then you can easily do:
WriteByteArray(file_1, 0, new byte[]);
WriteByteArray(file_2, 0, new byte[]);
WriteByteArray(file_3, 0, new byte[]);
but the con is, if you want to just write to one file then constantly typing that path or the string variable containing the path may make the code look a bit messy and unorganized.
The pros for the second way is basically the con for the first way all you do is:
File = "C:\\test.bin";
WriteByteArray(0, new byte[]);
WriteByteArray(0xFF, new byte[]);
WriteByteArray(0x2ACD, new byte[]);
but the con is the pro for the first way aka if you want to write the byte array into different file then you will always have to do File =...
Idk. Which is better? Which way is mostly used?
Since you feel there are pros and cons to both, then just implement both. This seems like a case where there is sufficient demand for either option, and creating one does not preclude the creation of another.
Also, since the first one doesn't require any state variables, make it static so the caller doesn't have to instantiate something just to call it.
Then have your instance method (that uses the File property) call the static method:
class FileWrapper
{
public string File { get; set; }
public static void WriteByteArray(string file, long offset, byte[] buffer)
{
// The real work goes here
}
public void WriteByteArray(long offset, byte[] buffer)
{
// Just call the static method and pass the instance property for the file path
WriteByteArray(this.File, offset, buffer);
}
}
The two interfaces are for entirely different use cases:
The first method, which could be made static, is for writing a buffer to a file at once; there should be no continuations, because the same file could be written in between of your program's writing it, creating a confusion.
The second method is for building a file incrementally from partial buffers. You set the file once, and then write to it until you are done. The class itself should have a Dispose method in order to participate in using statement.
Ultimately, the decision is up to you: pick the interface that matches your intended usage pattern.
Note: Note that since offset could mean an offset in a file or an offset in the buffer, consider renaming the second parameter to fileOffset or filePosition.
The second approach introduces sequential coupling, which is often an anti-pattern (and probably is in this case). It also introduces a global variable (see global variables are bad). So the first method is better (although there is probably a third option that is even better, such as creating an object like FileStream).
But assuming you want to choose from either the first option or second option, pick the first. If you are concerned about code turning out like this....
WriteByteArray(someLongVariableYouDontWantToType, myArray1);
WriteByteArray(someLongVariableYouDontWantToType, myArray2);
WriteByteArray(someLongVariableYouDontWantToType, myArray3);
WriteByteArray(someLongVariableYouDontWantToType, myArray4);
...I suggest you do this (which will also perform better)...
var outputBuffer = new List<byte>();
outputBuffer.AddRange(myArray1);
outputBuffer.AddRange(myArray2);
outputBuffer.AddRange(myArray3);
outputBuffer.AddRange(myArray4);
WriteByteArray(someLongVariableYouDontWantToType, outputBuffer.ToArray());
Or
WriteByteArray
(
someLongVariableYouDontWantToType,
(new[] { myArray1, myArray2, myArray3, myArray4 }).SelectMany(a => a)
);
...both of which concatenate the arrays and write them all in one go. The latter will perform better, but not everyone finds that sort of LINQ code easy to read.
If you did not mean to concatenate, but wish to replace, you should of course just use File.WriteAllBytes().
Since you expect to operate on the same file multiple times, it may be appropriate to use a Builder pattern to solve this problem. Or maybe it isn't. But it's interesting to discuss and could work as a decent answer. Let's have some fun and check it out!
Under the builder pattern, instead of this
WriteByteArray(someLongVariableYouDontWantToType, index1, myArray1);
WriteByteArray(someLongVariableYouDontWantToType, index2, myArray2);
WriteByteArray(someLongVariableYouDontWantToType, index3, myArray3);
WriteByteArray(someLongVariableYouDontWantToType, index4, myArray4);
You'd want your code to look something like this:
myFile
.WriteByteArray(index1, myArray1)
.WriteByteArray(index2, myArray2)
.WriteByteArray(index3, myArray3)
.WriteByteArray(index4, myArray4);
The first step is to create a type that will hold a string that is the file name. We want our own specific type for reasons that will become apparent in a moment. Here's a sample:
public class File
{
public string Path {get; private set; }
public File(string path)
{
Path = path;
}
}
You can use this class like this:
var myFile = new File("c:\temp\MyFileName.txt");
Now that we have a class, we can write an extension method on it:
static public class ExtensionMethods
{
static public File WriteBytes(this File path, int offset, IEnumerable<byte> buffer)
{
OpenFile(path); //Just as an example
SeekIndex(offset); //Just as an example
Write(buffer); //Just as an example
CloseFile(); //Just as an example
return path;
}
}
The key here is the return path line. Because of that, you can chain these together. Now we can do this:
File file = "c:\temp\fileName.txt";
file
.WriteByteArray(index1, myArray1)
.WriteByteArray(index2, myArray2)
.WriteByteArray(index3, myArray3)
.WriteByteArray(index4, myArray4);
Why did we want to use File and not just a string? Well, it would be pretty gauche to write an extension method for string that only works on certain types of strings. Hence the file-specific type.
Now there is one more (small) problem. Each call to WriteByteArray will probably open the file and close it again, which seems inefficient, since we only need to do that once. So in keeping with the builder pattern, we can add another method to signal completion.
static public class ExtensionMethods
{
static public File WriteBytes(this File path, int offset, IEnumerable<byte> buffer)
{
if (!IsFileOpen) OpenFile(path);
SeekIndex(offset);
Write(buffer);
return path;
}
static public void Commit(this File path)
{
CloseFile();
}
}
...which you can use like this:
File file = "c:\temp\fileName.txt";
file
.WriteByteArray(index1, myArray1)
.WriteByteArray(index2, myArray2)
.WriteByteArray(index3, myArray3)
.WriteByteArray(index4, myArray4)
.Commit();
This last part isn't mandatory, but may be a good idea if I/O performance is important to you.

gsapi_init_with_args is made: -100

I'm trying to build a PostScript to PDF Converter using Ghostscript.Net.
The Args that GetArgs return, are the ones I usually use to call gswin32c.exe and they work fine.
But every time i call Process, i get an error Saying "An error occured when call to 'gsapi_init_with_args' is made: -100". Googling that error didn't bring anything up so I thought I might ask here.
Are there differnet arguments to consider when calling the .dll directly with Ghostscript.net? Or did I made a mistake somewhere else?
Here's my class:
public class PdfConverter
{
#region Private Fields
private List<GhostscriptVersionInfo> _Versions = GhostscriptVersionInfo.GetInstalledVersions(GhostscriptLicense.GPL | GhostscriptLicense.AFPL | GhostscriptLicense.Artifex);
#endregion
#region Private Properties
private GhostscriptVersionInfo Version { get; set; }
#endregion
#region Construction
public PdfConverter()
{
Version = GhostscriptVersionInfo.GetLastInstalledVersion();
}
#endregion
#region Public Members
public bool ConvertToPdf(DirectoryInfo dir)
{
var d = dir;
if(!d.Exists)
return false;
var postScriptFiles = d.GetFiles("*.ps");
var pdfFiles = postScriptFiles.Select(psf => new FileInfo(Path.ChangeExtension(psf.FullName, ".pdf")));
foreach(var file in postScriptFiles) {
//ThreadPool.QueueUserWorkItem(new WaitCallback((o) => {
Process(file, new FileInfo(Path.ChangeExtension(file.FullName, ".pdf")));
//}));
}
pdfFiles.ForEach(pdf => pdf?.Refresh());
return pdfFiles.All(pdf => pdf.Exists);
}
#endregion
#region Private Helpers
private void Process(FileInfo inputFile, FileInfo outputFile)
{
Console.WriteLine($"Converting {inputFile} to {outputFile}");
var proc = new GhostscriptProcessor(Version, true);
proc.Process(GetArgs(inputFile, outputFile).ToArray(), new ConsoleStdIO(true, true, true));
}
private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
{
return new [] {
$"-q ",
$"-sDEVICE=pdfwrite",
$"-dSAFER",
$"-dNOPAUSE",
$"-dBATCH",
$"-sPAPERSIZE=a4",
$"-dEmbedAllFonts=true",
$"-dAutoRotatePages=/None",
$"-sOutputFile=\"{outputFile.FullName}\"",
$"-dCompatibilityLevel#1.4",
$"-c .setpdfwrite",
$"-f \"{inputFile.FullName}\""
};
}
#endregion
}
Edit:
I forgot to mention: To implement it i had to make my own GhostsdcriptStdIO class. I admit that I'm not entirely sure if I did this right. Although it does get instanciated without exceptions, and override StdOut(...) get's called, and the output is written to the console as expected. override void StdError(...) get's called as well. And also written to the console as expeted.
The Output of the error btw is:
"**** Could not open the file "c:\temp\test.pdf""
"**** Unable to open the initial device, quitting."
Here's my ConsoleStdIO class:
public class ConsoleStdIO : Ghostscript.NET.GhostscriptStdIO
{
#region Construction
public ConsoleStdIO(bool handleStdIn, bool handleStdOut, bool handleStdError) : base(handleStdIn, handleStdOut, handleStdError) { }
#endregion
#region Overrides
public override void StdError(string error)
{
var foo = Encoding.Default.GetBytes(error);
var lenght = foo.Length;
using (var err = Console.OpenStandardError()) {
if(err.CanWrite)
err.Write(foo, 0, lenght);
}
}
public override void StdIn(out string input, int count)
{
byte[] bytes = new byte[0];
using(var stdInput = Console.OpenStandardInput()) {
stdInput.Read(bytes, 0, count);
}
input = Encoding.Default.GetString(bytes);
}
public override void StdOut(string output)
{
var foo = Encoding.Default.GetBytes(output);
var lenght = foo.Length;
using (var err = Console.OpenStandardError()) {
if(err.CanWrite)
err.Write(foo, 0, lenght);
}
}
#endregion
}
Again: doing the same operation with the exact same files and arguments using gswin32c.exe works fine.
Happy Hacking
Error -100 is gs_error_Fatal, which means 'something catastrophic went wrong'. Its an indication that the program failed to start up properly and we can't tell why. The back channel may contain more information.
And indeed, the back channel tells you what's wrong:
**** Could not open the file "c:\temp\test.pdf
**** Unable to open the initial device, quitting.
Ghostscript is unable to open the output file, which means it can't open the pdfwrite device (because that requires an output file) so it aborts the operation.
There could be a number of reasons why Ghostscript can't open the output file. The first thing I'd do is trim down the number of arguments;
You don't want -q (quiet) when you are trying to debug a problem, you want all the information you can get.
I'd remove -dSAFER at least to start with, because that prevents Ghostscript accessing directories outside the current working directory and certain 'special' ones. It may well prevent you accessing the temp directory.
You don't need to set EmbedAllFonts when its the same value as the default.
You could drop the CompatibilityLevel (and note that you've used a # there instead of an =) switch, and the AutoRotatePages while getting this to work.
The "-c .setpdfwrite -f" string has been pointless for years but people still keep using it. All that does these days is slow down the start of processing, ditch it.
Finally you can try changing the backslash ('\') characters to forward slash ('/') in case your string handling is messing that up, or use double backslashes (I'd use the forward slash myself).
You should also check that c:\test\temp.pdf doesn't exist, or if it does exist is not read-only or already open in a different application.
So I solved the problem...
After taking KenS' advice I could run the application without Ghostscript (not Ghostscript.NET) giving me any errors. But it did not produce an actual PDF File.
So KenS's answer did not quite solve the problem, but since 'less is more' and since he took the time to talk to me on IRC to verify that my args in itself were correct, I'll give the answer points nonetheless.
What actually solved my was the following:
Here my original GetArgs(...)
private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
{
return new [] {
$"-sDEVICE=pdfwrite",
$"-dNOPAUSE",
$"-dBATCH",
$"-sPAPERSIZE=a4",
#"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts),
$"-sOutputFile={outputFile.FullName}",
$"{inputFile.FullName}",
};
}
Someone in #csharp pointed out to me, that in c, the first argument is always the name of the command. So he suggested to just put "gs" as the first argument (as a dummy) and try... And that's what actually solved my problem.
So this is how the working GetArgs(...) looks:
private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
{
return new [] {
$"gs",
$"-sDEVICE=pdfwrite",
$"-dNOPAUSE",
$"-dBATCH",
$"-sPAPERSIZE=a4",
#"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts),
$"-sOutputFile={outputFile.FullName}",
$"{inputFile.FullName}",
};
}

C# - my ReadLine() gives me a null value when I should get a string

Solved - Accidentally wiped the actual file of data but the ide doesn't update that file unless you reopen it so I thought the data was still in there.
I'm working on a project in C# that reads in a fake inventory and then transactions to go with that inventory in another class. I know the code is quite messy at the moment, i'm just trying to figure out one thing specifically.
this code here will read in my file "Inventory.in", check if the file exists(which it does) and then start my streamreader and readline into a string.
private void btnFill_Click(object sender, EventArgs e)
{
string strInputLine;
string inFile = "Inventory.in";
StreamReader iSR;
InvRec currInvent;
if (File.Exists(inFile))
{
iSR = new StreamReader(inFile);
strInputLine = iSR.ReadLine();
while (strInputLine != null)
{
all of it isn't there but the point of emphasis is that the
"strInputLine = iSR.ReadLine();"
does indeed give me the correct value from that file.
now moving on to my question, the second block of code from another button is below:
private void btnProcess_Click(object sender, EventArgs e)
{
string strInputVal;
string inFileName = "Transactions.in";
TransRec currTrans;
StreamReader iSR2;
transListClass transactionList = new transListClass();
InvRec inventItem = inventoryList.Retrieve();
if (File.Exists(inFileName))
{
iSR2 = new StreamReader(inFileName);
strInputVal = iSR2.ReadLine();
while (strInputVal != null)
{
my problem lies when I try and do my ReadLine() into iSR2. it gives me null instead of the value from the file I'm supposed to get. Everything is the same otherwise, it just refuses to give me the correct value. I'm following the debugger in Visual Studio 2010, so I know the file is found and exists, I see it being opened, just a null value instead of my string I need.
Thank you to anybody in advance, I appreciate it.
-Anthony
edit:
the second block of code is supposed to read from "Transactions.in" instead of the first one that reads from "Inventory.in"
Important edit:
I have noticed when i changed "Transactions.in" to "Inventory.in" in the second block of code for the process button, it reads the values from Inventory.in and gives me a proper string unlike null from Transactions.in. The file is found and is just a text file named Transactions.in that was provided by my teacher, nobody else had a problem with it.

external fill of parameters' function, help please [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have implemented a method that requires 2 parameters (arguments) : the first one is the source of the xml file ( type string) and the second one is the destination path of the generated pdf file (type string)
This application will be used by another application that will assign automatically the 2 parameters.
My question is how should I declare the 2 arguments until I can assign external parameters?
in other meaning : I implemented a console appication . When calling it from cmd , it looks like that : C:> name_of_apllication "path1" "path2". How should I implement the parameters if the called method until they will replaced by "path1" and "path2"?
this is the code of the main class : the method that will be used is : GeneratePDF_CTAF
static void Main(string[] args)
{
string input = "";
string output = "";
GeneratePDF.GeneratePDF_Ctaf( ref input, ref output );
}
this is the error screen , it is in french and that means can not find file
The command line arguments are passed to the Main method as an array of strings. This is the args parameter in your code, so you can simply extract the parameters you need from there:
static int Main(string[] args)
{
if (args.Length != 2)
{
Console.Error.WriteLine("This program requires exactly 2 parameters");
return 1; // error code
}
string input = args[0];
string output = args[1];
GeneratePDF.GeneratePDF_Ctaf(input, output);
return 0; // no error
}
Note here, I've modified Main to return an int. A non-zero return value is often used in console applications to provide error information to the calling program. I've also removed the ref keyword from your parameters because it's almost never necessary to use ref parameters in .NET.
I think there is something fundamental about using a function that you are not understanding so I will give a short example -- if it does not solve your problem please explain why not:
void Main(string[] args)
{
aFunction(args[1], args[2]);
}
void aFunction(string arg1, string arg2)
{
Console.WriteLine(arg1);
Console.WriteLine(arg2);
}

Categories

Resources