I've been working for the last few days on a method to compress 144 million tile representation for my xna game down to a very small size when saved. Having managed to pull that off I now find myself stumped on how to go about getting them back from the file in chunks.
In the file I have.
An integer (it gets compressed to bytes using the 7BitEncodedInt method)
A byte
The compressed integer represents the number of tiles and the byte that follows determines what type the tiles are. This is all well and good and works really well. Most importantly it shrinks the file size down to just 50mb on average.
The problem is that I am currently reading back the entire file.
From the file I'm getting this.
The index value of each tile (just a basic iteration as I grab the tiles)
The type for each tile as a byte value
A byte value representing a texture for that tile (this is hard to explain but its necessary on a per tile basis)
The end result of all this is that I'm managing to save the file and only use about 50mb. But by loading the whole thing back in it expands out to nearly 1.5gigs on the ram. I can't really afford to sacrifice anymore tile info. so I need a way to only load portions of the map based on the player location. The goal is to be around the 100-200mb range
I have been looking at memory mapping the file, using quadtrees, pretty much anything I could find for loading files in chunks. While these options all seem pretty good I'm not sure which is best or if given the situation there may be another even better one. The other problem with all this is that these solutions all seem very involved (especially since this is my first time using them) and while I'm not against devoting myself to some lengthy coding I'd like to know that its gonna do what I need it to before hand.
My question is, given how I have to process the file as I pull it in and the fact that it needs to be done based on the players location what would be the best way to do this ? I'm just looking for some direction here. Code is always welcome but not required.
You want to have fixed length variables in your Tile class and implement something like such:
This is an example of a collection class (People) that can get a value based on index from a collection that was serialised into a file.
Person is the class that is the base of the People collection.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FileStreamDatabaseTest
{
class Program
{
static void Main(string[] args)
{
People.OpenCollection();
People.Test_WillOverwriteData();
People.CloseCollection();
Console.ReadLine();
}
}
public class Person
{
// define maxium variable sizes for serialisation
protected static int pMaxLength_FirstName = 64;
protected static int pMaxLength_Age = 10;
public static int MaxObjectSize
{
get
{
// return the sum of all the maxlegnth variables to define the entire object size for serialisation
return pMaxLength_FirstName + pMaxLength_Age;
}
}
// define each object that will be serialised as follows
protected string pFirstName;
public string Firstname
{
set
{
// ensure the new value is not over max variable size
if (value.Length > pMaxLength_FirstName)
throw new Exception("the length of the value is to long.");
pFirstName = value;
}
get
{
return pFirstName;
}
}
protected int pAge;
public int Age
{
get
{
return pAge;
}
set
{
pAge = value;
}
}
public byte[] Serialise()
{
// Output string builder
StringBuilder Output = new StringBuilder();
// Append firstname value
Output.Append(Firstname);
// Add extra spaces to end of string until max length is reached
if (Firstname.Length < pMaxLength_FirstName)
for (int i = Firstname.Length; i < pMaxLength_FirstName; i++)
Output.Append(" ");
// Append age value as string
Output.Append(Age.ToString());
// Add extra spaces to end of string until max length is reached
int AgeLength = Age.ToString().Length;
if (AgeLength < pMaxLength_Age)
for (int i = AgeLength; i < pMaxLength_Age; i++)
Output.Append(" ");
// Return the output string as bytes using ascii encoding
return System.Text.Encoding.ASCII.GetBytes(Output.ToString());
}
public void Deserialise(byte[] SerialisedData)
{
string Values = System.Text.Encoding.ASCII.GetString(SerialisedData);
pFirstName = Values.Substring(0, pMaxLength_FirstName).Trim();
pAge = int.Parse(Values.Substring(pMaxLength_FirstName, pMaxLength_Age).Trim());
}
}
public static class People
{
private static string tileDatasource = #"c:\test.dat";
private static System.IO.FileStream FileStream;
public static void OpenCollection()
{
FileStream = new System.IO.FileStream(tileDatasource, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None);
}
public static void CloseCollection()
{
FileStream.Close();
FileStream.Dispose();
FileStream = null;
}
public static void SaveCollection(Person[] People)
{
FileStream.SetLength(People.Length * Person.MaxObjectSize);
FileStream.Position = 0;
foreach (Person PersonToWrite in People)
{
// call serialise to get bytes
byte[] OutputBytes = PersonToWrite.Serialise();
// write the output buffer
// note: this will always be the same size as each variable should
// append spaces until its max size is reached
FileStream.Write(OutputBytes, 0, OutputBytes.Length);
}
}
public static Person GetValue(int Index)
{
// set the stream position to read the object by multiplying the requested index with the max object size
FileStream.Position = Index * Person.MaxObjectSize;
// read the data
byte[] InputBytes = new byte[Person.MaxObjectSize];
FileStream.Read(InputBytes, 0, Person.MaxObjectSize);
// deserialise
Person PersonToReturn = new Person();
PersonToReturn.Deserialise(InputBytes);
// retun the person
return PersonToReturn;
}
public static void Test_WillOverwriteData()
{
long StartTime;
long EndTime;
TimeSpan TimeTaken;
Console.WriteLine("-------------------------------------------------------------------");
Console.WriteLine("*** Creating 2,000,000 test people... ");
StartTime = DateTime.Now.Ticks;
Person[] People = new Person[2000000];
for (int i = 0; i < 2000000; i++)
{
People[i] = new Person();
People[i].Firstname = "TestName." + i;
People[i].Age = i;
}
EndTime = DateTime.Now.Ticks;
TimeTaken = new TimeSpan(EndTime - StartTime);
Console.WriteLine("-> Completed in " + TimeTaken.TotalSeconds + " seconds");
Console.WriteLine("-------------------------------------------------------------------");
Console.WriteLine("*** Serialising Collection to disk... ");
StartTime = DateTime.Now.Ticks;
SaveCollection(People);
EndTime = DateTime.Now.Ticks;
TimeTaken = new TimeSpan(EndTime - StartTime);
Console.WriteLine("-> Completed in " + TimeTaken.TotalSeconds + " seconds");
Console.WriteLine("-------------------------------------------------------------------");
Console.WriteLine("*** Redundancy Test... ");
StartTime = DateTime.Now.Ticks;
bool Parsed = true;
int FailedCount = 0;
for (int i = 0; i < 2000000; i++)
{
if (GetValue(i).Age != i)
{
Parsed = false;
FailedCount++;
}
}
EndTime = DateTime.Now.Ticks;
TimeTaken = new TimeSpan(EndTime - StartTime);
Console.WriteLine("-> " + (Parsed ? "PARSED" : "FAILED (" + FailedCount + " failed index's"));
Console.WriteLine("-> Completed in " + TimeTaken.TotalSeconds + " seconds");
Console.WriteLine("-------------------------------------------------------------------");
Console.WriteLine("*** Reading 10,000 index's at once... ");
StartTime = DateTime.Now.Ticks;
Person[] ChunkOfPeople = new Person[10000];
for (int i = 0; i < 10000; i++)
ChunkOfPeople[i] = GetValue(i);
EndTime = DateTime.Now.Ticks;
TimeTaken = new TimeSpan(EndTime - StartTime);
Console.WriteLine("-> Completed in " + TimeTaken.TotalSeconds + " seconds");
Console.WriteLine("-------------------------------------------------------------------");
Console.WriteLine("*** Reading 100,000 index's at once... ");
StartTime = DateTime.Now.Ticks;
ChunkOfPeople = new Person[100000];
for (int i = 0; i < 100000; i++)
ChunkOfPeople[i] = GetValue(i);
EndTime = DateTime.Now.Ticks;
TimeTaken = new TimeSpan(EndTime - StartTime);
Console.WriteLine("-> Completed in " + TimeTaken.TotalSeconds + " seconds");
Console.WriteLine("-------------------------------------------------------------------");
Console.WriteLine("*** Reading 1,000,000 index's at once... ");
StartTime = DateTime.Now.Ticks;
ChunkOfPeople = new Person[1000000];
for (int i = 0; i < 1000000; i++)
ChunkOfPeople[i] = GetValue(i);
EndTime = DateTime.Now.Ticks;
TimeTaken = new TimeSpan(EndTime - StartTime);
Console.WriteLine("-> Completed in " + TimeTaken.TotalSeconds + " seconds");
}
}
}
There are a number of options, not all of them may be appropriate for your particular project:
Don't use a single file for all the data. Divide the map in smaller "rooms" and store each one in its own file. Load only the "room" the player starts in and preemptively load neighboring "rooms" and unload old ones.
Reduce the number of tiles you need to store. Use procedural generation to create an area's layout.
If you have a 10x10 room with the floor made of a single tile type then don't store 100 separate tiles but instead use a specific marker that says "this area has a 10x10 floor with this tile". If it's a wall then save the start and end positions and the texture type. If you have a multi-tile doodad in the middle of an open field and it's position is not relevant to the story then position it randomly in the field (and save the seed for the random number generator in the map file so next time it will appear in the same place).
Related
I have to prepare Logger class which will be saving data from 3 structs in interval of 10-15 ms. My approach to this problem is below:
public class Logger
{
// Variables
private Task loggerTask;
public bool IsActive { get; set; }
// Constructor
public Logger()
{
}
private void Logging()
{
#if DEBUG
System.Diagnostics.Debug.WriteLine("Logging has been started.");
#endif
FileStream fs = new FileStream($"./log {DateTime.Now.ToString("dd.MM HH.mm.ss")}.txt", FileMode.Create, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs, Encoding.Default);
try
{
Queue<double> times = new Queue<double>();
Queue<Attitude> attitudes = new Queue<Attitude>();
Queue<LocalPositionNed> positions = new Queue<LocalPositionNed>();
Queue<SetPositionTargetLocalNed> setpoints = new Queue<SetPositionTargetLocalNed>();
// Logs data
DateTime start = DateTime.Now;
DateTime last = start;
DateTime now;
while (IsActive)
{
now = DateTime.Now;
if ((now - last).TotalMilliseconds < 16)
continue;
last = now;
times.Enqueue((now - start).TotalMilliseconds);
attitudes.Enqueue(GCS.Instance.Drone.Attitude);
positions.Enqueue(GCS.Instance.Drone.LocalPositionNed);
setpoints.Enqueue(GCS.Instance.Offboard.SetPoint);
}
// Save data
for(int i = 0; i < times.Count; i++)
{
sw.WriteLine($"{times.ElementAt(i)}\t" +
$"{attitudes.ElementAt(i).Pitch}\t" +
$"{attitudes.ElementAt(i).Roll}\t" +
$"{attitudes.ElementAt(i).Yaw}\t" +
$"{attitudes.ElementAt(i).Pitchspeed}\t" +
$"{attitudes.ElementAt(i).Rollspeed}\t" +
$"{attitudes.ElementAt(i).Yawspeed}\t" +
$"{positions.ElementAt(i).X}\t" +
$"{positions.ElementAt(i).Y}\t" +
$"{positions.ElementAt(i).Z}\t" +
$"{positions.ElementAt(i).Vx}\t" +
$"{positions.ElementAt(i).Vy}\t" +
$"{positions.ElementAt(i).Vz}\t" +
$"{setpoints.ElementAt(i).Vx}\t" +
$"{setpoints.ElementAt(i).Vy}\t" +
$"{setpoints.ElementAt(i).Vz}\t");
}
}
catch (Exception ex)
{
#if DEBUG
System.Diagnostics.Debug.WriteLine($"Logging exception: {ex.Message}");
#endif
}
finally
{
sw.Dispose();
fs.Dispose();
}
#if DEBUG
System.Diagnostics.Debug.WriteLine("Logging has been ended.");
#endif
}
// Static method
public void Start()
{
IsActive = true;
loggerTask = new Task(Logging);
loggerTask.Start();
}
public void Stop()
{
IsActive = false;
}
}
I have problem with intervals, because they are varying about 5-8 ms. My project requires maximum varying of 1-2 ms. Does anyone have idea how I can improve my approach.
Thank you for your responses.
The biggest issue is probably using DateTime.Now, this has poor resolution and is not appropriate for this kind of task.
A simple alternative that would be more appropriate is a stopwatch.
var delay = 16;
var stopwatch = Stopwatch.StartNew();
long current = 0;
long previous;
var next = stopwatch.ElapsedMilliseconds + delay;
for (int i = 0; i < 100; i++)
{
while (next > stopwatch.ElapsedMilliseconds)
{
// Spin
}
next = stopwatch.ElapsedMilliseconds + delay;
previous = current;
current = stopwatch.ElapsedMilliseconds;
var delta = current - previous;
Console.WriteLine("Delta: " + delta);
}
As mentioned in the comments, this does not provide any strong guarantees, merely a best effort. There are also better ways to do this that does not waste an entire thread doing nothing, for example using multi media timers. But it might be adequate for testing/debugging purposes as long as the load on the CPU is light.
I am fairly new to C# (using it for a crpytographic process).
Some help would be greatly appreciated!
I have made a timer that should print out my hash speed every minute. See code below
using System;
using System.Text;
using System.Security.Cryptography;
namespace HashConsoleApp {
class Program {
static void Main(string[] args) {
long Nonce = 19989878659;
long Noncestart = 19989878659;
int Tick = 0;
DateTime start = DateTime.UtcNow;
while (Tick == 0) {
string noncestr = Nonce.ToString();
string plainData = "1" + noncestr + "Sjoerd0000000000000000000000000000000000000000000000000000000000000000";
string hashedData = ComputeSha256Hash(plainData);
// if 10-zeroes hash is found, save to disk
if (hashedData.Substring(0, 10) == "0000000000") {
Tick = Tick + 1;
string writestring = "Nonce: " + noncestr + "\n" + "hashed data: " + hashedData;
System.IO.File.WriteAllText("hash_10.txt", writestring);
}
// print hash speed per second, each minute
DateTime end = DateTime.UtcNow;
TimeSpan span1 = end.Subtract(start);
TimeSpan span2 = end.Subtract(start);
if (span1.Minutes >= 1) {
long diff = (int)(Nonce - Noncestart) / 60;
string diffs = diff.ToString();
Console.Write("Hash speed: " + diffs + " h/s");
System.IO.File.WriteAllText("test.txt", Nonce.ToString());
Noncestart = Nonce;
span1 = TimeSpan.Zero;
}
// save Nonce every hour, reset clock
if (span2.Minutes >= 60) {
start = DateTime.UtcNow;
System.IO.File.WriteAllText("hourly_nonce.txt", Nonce.ToString());
span2 = TimeSpan.Zero;
}
//Console.WriteLine("Raw data: {0}", plainData);
//Console.WriteLine("Hash {0}", hashedData);
//Console.WriteLine(ComputeSha256Hash("1"+noncestr+"Sjoerd0000000000000000000000000000000000000000000000000000000000000000"));
}
}
static string ComputeSha256Hash(string rawData) {
// Create a SHA256
using(SHA256 sha256Hash = SHA256.Create()) {
// ComputeHash - returns byte array
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
// Convert byte array to a string
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++) {
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
}
}
However, after the 1 minute mark this repeadetly keeps on printing on my screen. it looks like it gets stuck in the if statement. Is there something wrong with my code?
This should do the trick for your minute-timer (resetting minuteStart instead of span1):
static void Main(string[] args) {
long Nonce = 19989878659;
long Noncestart = 19989878659;
int Tick = 0;
DateTime start = DateTime.UtcNow;
DateTime minuteStart = DateTime.UtcNow; // ##### (added)
while (Tick == 0) {
// [Process stuff]
// print hash speed per second, each minute
DateTime end = DateTime.UtcNow;
TimeSpan span1 = end.Subtract(minuteStart); // ##### (modified)
if (span1.TotalMinutes >= 1) { // ##### (modified but Minutes should work fine here)
long diff = (int)(Nonce - Noncestart) / 60;
string diffs = diff.ToString();
Console.Write("Hash speed: " + diffs + " h/s");
System.IO.File.WriteAllText("test.txt", Nonce.ToString());
Noncestart = Nonce;
minuteStart = DateTime.UtcNow; // ##### (added)
//span1 = TimeSpan.Zero; // ##### (deleted)
}
// [...]
}
}
(See the lines with // #### comments)
The trick is that resetting span1 is useless because of this line:
TimeSpan span1 = end.Subtract(start);
However, if (span2.Minutes >= 60) will never be entered, as TimeSpan.Minutes "ranges from -59 through 59".
You probably are looking for TotalMinutes here.
Your if (span1.Minutes >= 1) { statement won't mean the printout only occurs once per minute, it will simply cause it to print whenever at least one minute has passed since the program started.
You need to check whether 1 minute has passed since the last printout . Therefore you need to reset the start time every time you run a printout. (N.B. Setting span1 = TimeSpan.Zero as you do now has no effect because you just overwrite that as soon as the loop runs again).
Also your minute and hour tests will conflict with each other once you do this, so you need separate date counters.
So add
DateTime start2 = DateTime.UtcNow;
just below the line where you declare start already.
Then please replace span1 = TimeSpan.Zero; with
start2 = DateTime.UtcNow;
and change TimeSpan span1 = end.Subtract(start);
to
TimeSpan span1 = end.Subtract(start2);
Lastly, replace if (span2.Minutes >= 60) { with
if (span2.TotalMinutes >= 60) {
otherwise this part won't work either because Minutes only reports the minutes in the current hour. You can also remove span2 = TimeSpan.Zero;, this is redundant like the similar line in the first if block.
I am trying to read from each line in a file and grab specific strings and integers. However the values of the found integers are not added up at the end and i'm unsure why. I apologize if this is a simple error.
If a line in the file contains "Event Type: Music", store "Music" in the EventType[] array using MusicTrace. Music trace begins at 0 and increments each time the string above is found. So it works its way down the array. the array size is the amount of lines in the file to ensure there is always enough array space.
I have another Array for attendance named EventAttendance[] which does the same steps above, but cuts the first 18 characters from the found line giving the remaining number (the line in the file is a fixed length). AttendanceTrace is used in the same manner a the above MusicTrace.
I then have a loop for the EventAttendance array which uses i and starts at 0 and carries out code until the EventAttendance.Length property is reached. The code adds up the total attendance from each EventAttendance[] index using i
The code is below:
private void frmActivitiesSummary_Load(object sender, EventArgs e)
{
if (File.Exists(sVenueName.ToString() + ".txt"))
{
using (StreamReader RetrieveEvents = new StreamReader(sVenueName.ToString() + ".txt")) //Create a new file with the name of the username variable
{
string[] ReadLines = File.ReadAllLines(sVenueName + ".txt"); //Read File
int MusicTrace = 0;
int AttendanceTrace = 0;
string[] EventType = new string[ReadLines.Length]; //Store found event types
int[] EventAttendance = new int[ReadLines.Length]; //Store Event Attendance
string line; //Declare String to store line
using (StreamReader file = new StreamReader(sVenueName + ".txt")) //Using StreamReader
{
while (!file.EndOfStream)
{
line = file.ReadToEnd();
//Get All Music Event to Array
if (line.Contains("Event Type: Music"))
{
EventType[MusicTrace] = "Music"; //[0] = Music
if (MusicTrace != 0)
MusicTrace = MusicTrace + 1;
else
MusicTrace = 1;
}
//Get All attendances to Array
if (line.Contains("People Attending:"))
{
line.Remove(0, 18);
int ConvertedLine = Convert.ToInt32(line);
EventAttendance[AttendanceTrace] = ConvertedLine; //[0] = 10
if (AttendanceTrace != 0)
AttendanceTrace = AttendanceTrace + 1;
else
AttendanceTrace = 1;
}
}
}
//for each array index and if array index contains music, add this to total amount of music events
for (int i = 0; i <= EventAttendance.Length; i++)
{
if (EventAttendance[i] > 0)
{
if (iMusicAttendance > 0)
iMusicAttendance = iMusicAttendance + EventAttendance[i];
else
iMusicAttendance = EventAttendance[i];
}
}
}
}
}
The Attendance is then show on the click on a button:
private void btnShow_Click(object sender, EventArgs e)
{
lblMusicOutput.Text = "After analysis, we can see that Music Events have a total attendance of " + iMusicAttendance;
lblArtOutput.Text = "After Analysis, we can see that Events have a total Attenance of " + iArtAttendance;
lblDance.Text = "After Analysis, we can see that Dance Events have a total Attenance of " + iDanceAttendance;
lblTheatreOutput.Text = "After Analysis, we can see that Theatre Events have a total Attenance of " + iTheatreAttendance;
}
There where a several useless variables inside your code, that I took the liberty to remove. I also changed arrays for List<T> in order to use Linq.
You were adding a Convert.ToIn32 with the full line, because String.Remove() doesn't change the object it's called on but return a new string that you have to assign to something : line = line.Remove(0, 18);
Also, you were doing useless checks for the counters:
if (MusicTrace != 0)
MusicTrace = MusicTrace + 1;
else
MusicTrace = 1;
is the same than
MusicTrace++;
which leads us to:
if (!File.Exists(sVenueName.ToString() + ".txt"))
return;
List<String> EventType = new List<string>(); //Store found event types
List<int> EventAttendance = new List<int>(); //Store Event Attendance
using (StreamReader file = new StreamReader(sVenueName + ".txt")) //Using StreamReader
{
while (!file.EndOfStream)
{
var line = file.ReadLine(); //Declare String to store line
//Get All Music Event to Array
if (line.Contains("Event Type: Music"))
{
EventType.Add("Music"); //[0] = Music
}
//Get All attendances to Array
if (line.Contains("People Attending:"))
{
line = line.Remove(0, 18);
EventAttendance.Add(Convert.ToInt32(line)); //[0] = 10
}
}
}
//for each array index and if array index contains music, add this to total amount of music events
iMusicAttendance = EventAttendance.Sum();
Please change :
while (!file.EndOfStream)
{
line = file.ReadToEnd();
to
while (!file.EndOfStream)
{
line = file.ReadLine();
explanation:
You are reading the entire file at once, then you check once your two conditions. But you want to read line by line. So you need to use ReadLine.
As for the rest, you declare but never use the StreamReader RetrieveEvents. You can get rid of it.
You can use List<T> to store the read information. This way you get more flexibility into your code. And the Sum can be calculated without a loop.
EDIT:
I took the liberty to cut down your programm a little. The Code below should do exactly what you describe in your post:
string[] allLines = File.ReadAllLines(sVenueName + ".txt");
List<string> EventType = allLines.Where(x => x.Contains("Event Type: Music"))
.Select(x => x = "Music").ToList();
List<int> EventAttendance = allLines.Where(x => x.Contains("People Attending:"))
.Select(x => Convert.ToInt32(x.Remove(0,18))).ToList();
int iMusicAttendance = EventAttendance.Sum();
EDIT2:
seeing your file content it becomes obvious that you want only to sum up the attending people of the music event, but in your approach you sum up all attending people of all event.
Looking at your file it seems you have an offset of 3 lines. So I would suggest, to get all indices of the Music lines and then grab only the numbers that are 3 lines further:
List<string> allLines = File.ReadAllLines("input.txt").ToList();
List<int> indices = Enumerable.Range(0, allLines.Count)
.Where(index => allLines[index].Contains("Event Type: Music"))
.Select(x => x+=3).ToList();
List<int> EventAttendance = allLines.Where(x => indices.Contains(allLines.IndexOf(x))).Select(x => Convert.ToInt32(x.Remove(0,18))).ToList();
int iMusicAttendance = EventAttendance.Sum();
This will get you the sum of only the music people ;) hop it helps.
My program reads in multiple files that contain time/value pairs sampled at different rates. I'm trying to use the file with the highest sample rate as the time scale for all sampled rates and output one master file with the unique time values from the highest sample rate file.
Each file contains time/values pairs like:
1,58
1.5,90
2,154
2.5,34
Here is my code so far:
public void ReadAndWrite(string[] fileNames)
{
var stopwatch = Stopwatch.StartNew();
List<StreamReader> readers = fileNames.Select(f => new StreamReader(f)).ToList();
try
{
using (StreamWriter writer = new StreamWriter(tbxOutputFile.Text))
{
string line = null;
// For each measurement in max measurements
for (int measNum = 0; measNum < numOfRows; measNum++)
{
// For each file's reader
for (int i = 0; i < readers.Count; i++)
{
// If line contains something, then add it to line
if ((line = readers[i].ReadLine()) != null)
{
// Process line and then write it to file
line = ProcessLine(line);
writer.Write(line);
}
else
{
writer.Write("");
}
// If it's not the last column, add delimiter
if (i < readers.Count - 1)
writer.Write(",");
}
writer.WriteLine();
// Update labels
int val = ((measNum + 1) * 100) / numOfRows;
string newText = Convert.ToString("Progress: " + val + "% " + " " + "Measurement #: " + (measNum + 1)
+ " out of " + numOfRows); // running on worker thread
this.Invoke((MethodInvoker)delegate
{
// runs on UI thread
lblStatus.Text = newText;
progressBar1.Value = val;
});
}
}
}
catch (Exception)
{
throw;
}
finally
{
foreach (var reader in readers)
{
reader.Close();
}
}
MessageBox.Show("File successfully created! " + '\n' + "Elapsed time: " +
(stopwatch.ElapsedMilliseconds/1000) + " seconds", "Processing Complete");
}
I came up with the pseudo code below (currentTime is the time from each file and uniqueTime is from an array that reads in each time from the highest sampled file):
// if time value from individual file is same as uniqueTime
if currentTime == uniqueTime
{
valueToWrite = curr_value // write the current value
}
else // currentTime is not same as uniqueTime
{
valueToWrite = prev_value // write the previous value
}
timeToWrite = uniqueTime // always write the uniqueTime
What is the best way to execute this pseudo code to make a unique time reference for all the various sample rates? Sorry if my question is confusing, I can elaborate more if need be.
To be clear about this, you do not want the values at the specific time they occurred, but you want to display one value for each source at each timepoint that the highest sampled source has?
That should be pretty straightforward. In pseudocode:
foreach (ValuePair val in highSampleRateValues) {
var aggregatedTimePointData;
aggregatedTimePointData.Add(val.Time, val.Value);
foreach (ValuePair val2 in lowSampleRateValues) {
var value = DetermineLatestEntryBackwardFrom(val.Time);
aggregatedTimePointData.Add(value);
}
}
This way, the sample rate of the higher density sampled signal serves as a clock, but you will have inaccuracies since the values from the other sources are only close, but not exactly on the timepoint of their recording. If you want those inaccuracies reduced, choose a higher sample rate and do the same thing. You can get as close to the actual timepoints as you want.
I am making a password generator which can generate a password.
var listOfCharacters = "abcdefghijklmnopqrstuvwxyz" //the chars which are using
chars = listOfCharacters.ToCharArray();
string password = string.Empty;
for (int i = 0; i < length; i++)
{
int x = random.Next(0, chars.Length); //with random he is picking a random char from my list from position 0 - 26 (a - z)
password += chars.GetValue(x); // putting x (the char which is picked) in the new generated password
}
if (length < password.Length) password = password.Substring(0, length); // if the password contains the correct length he will be returns
return password;
My random:
random = new Random((int)DateTime.Now.Ticks);
I am looking for a faster way to generate a password than using Ticks, because its not fast enough for me. I am looking for a simple code which i can easy put in my above code. I am just a beginner in C#. So that i still can use int x = random.Next(0, chars.Length); but instead of Random.next a faster one.
EDIT:
When i want two generate two passwords in a short time .Ticks is to slow
My test code:
[TestMethod]
public void PasswordGeneratorShouldRenderUniqueNextPassword()
{
// Create an instance, and generate two passwords
var generator = new PasswordGenerator();
var firstPassword = generator.Generate(8); //8 is the length of the password
var secondPassword = generator.Generate(8);
// Verify that both passwords are unique
Assert.AreNotEqual(firstPassword, secondPassword);
}
You could use the hashcode of a Guid as seed value for your Random instance. It should be random enough for your case.
random = new Random(Guid.NewGuid().GetHashCode());
Either create the Random instance once at startup or use the RNGCryptoServiceProvider.
// Create the random instance only once.
private static Random _Random = new Random();
static void Main(string[] args)
{
var listOfCharacters = "abcdefghijklmnopqrstuvwxyz".ToList();
var result = new StringBuilder();
for (int i = 0; i < 20; i++)
{
// Consider creating the provider only once!
var provider = new RNGCryptoServiceProvider();
// The same is true for the byte array.
var bytes = new byte[4];
provider.GetBytes(bytes);
var number = BitConverter.ToInt32(bytes, 0);
var index = Math.Abs(number % listOfCharacters.Count);
result.Append(listOfCharacters[index]);
}
Console.WriteLine(result.ToString());
Console.ReadKey();
}
Bias testing
static void Main(string[] args)
{
var listOfCharacters = "abcdefghijklmnopqrstuvwxyz".ToList();
var occurences = new Dictionary<char, int>();
foreach (var character in listOfCharacters)
{
occurences.Add(character, 0);
}
var provider = new RNGCryptoServiceProvider();
var bytes = new byte[4];
for (int i = 0; i < 1000000; i++)
{
provider.GetBytes(bytes);
var number = BitConverter.ToInt32(bytes, 0);
var index = Math.Abs(number % listOfCharacters.Count);
occurences[listOfCharacters[index]]++;
}
var orderedOccurences = occurences.OrderBy(kvp => kvp.Value);
var minKvp = orderedOccurences.First();
var maxKvp = orderedOccurences.Last();
Console.WriteLine("Min occurence: " + minKvp.Key + " Times: " + minKvp.Value);
Console.WriteLine("Max occurence: " + maxKvp.Key + " Times: " + maxKvp.Value);
Console.WriteLine("Difference: " + (maxKvp.Value - minKvp.Value));
Console.ReadKey();
}
The result is that between the highest occurrence and the lowest is a value somewhere between 700 - 800 which means the bias is somewhere at 0.08% and the two characters with the maximum difference always differs. So i really can't see any bias.
The following program generates ~500 passwords / millisecond on my computer:
class Program
{
static void Main(string[] args)
{
var g = new Generator();
IEnumerable<string> passwords = new List<string>();
var startTime = DateTime.Now;
passwords = g.GetPassword().ToList();
}
}
class Generator
{
Random r = new Random(Guid.NewGuid().GetHashCode());
string randomCharsList;
const int length = 8;
const int randomLength = 8000;
const string listOfCharacters = "abcdefghijklmnopqrstuvwxyz";
public Generator()
{
CreateRandom();
}
private void CreateRandom()
{
var randomChars = new StringBuilder();
string password = string.Empty;
for (int i = 0; i < randomLength + length; i++)
{
var random = new Random(i * Guid.NewGuid().ToByteArray().First());
int x = random.Next(0, listOfCharacters.Length);
randomChars.Append(listOfCharacters[x]);
}
randomCharsList = randomChars.ToString();
}
public IEnumerable<string> GetPassword()
{
int pos;
var startTime = DateTime.Now;
while ((DateTime.Now - startTime).Milliseconds < 1)
{
pos = r.Next(randomLength);
yield return randomCharsList.Substring(pos, length);
}
}
}
Just wanted to add a note here about the thread safety issue in generating random numbers (such as a high volume webserver where we ran into this issue).
Essentially, Random class is NOT thread safe and if collision occurs, it will return 0 (not what i expected) which needless to say can really wreak havoc in your logic :) So if using in a multi-threaded environment then make sure to protect access to any shared Random objects.
See section on the 'The System.Random class and thread safety' at https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx for more details.
Hope this helps someone.