Я занимаюсь разработкой приложения для формы Windows, которое берет программу робота, созданную другим программным обеспечением, и модифицирует ее.Процесс модификации выглядит следующим образом:
- StreamReader.ReadLine () используется для анализа файла строка за строкой
- Regex используется для поиска определенных ключевых слов в файле.Если совпадение получено, совпавшая строка копируется в другую строку и заменяется новыми строками кода робота.
Измененный код сохраняется в строке и, наконец, записывается в новый файл.
Вся коллекция совпадающих строк, полученная с помощью Regex, также сохраняется в строке и, наконец, записывается в новый файл.
Я смог успешно сделать это
private void Form1_Load(object sender, EventArgs e)
{
string NextLine = null;
string CurrLine = null;
string MoveL_Pos_Data = null;
string MoveL_Ref_Data = null;
string MoveLFull = null;
string ModCode = null;
string TAB = "\t";
string NewLine = "\r\n";
string SavePath = null;
string ExtCode_1 = null;
string ExtCode_2 = null;
string ExtCallMod = null;
int MatchCount = 0;
int NumRoutines = 0;
try
{
// Ask user location of the source file
// Displays an OpenFileDialog so the user can select a Cursor.
OpenFileDialog openFileDialog1 = new OpenFileDialog
{
Filter = "MOD Files|*.mod",
Title = "Select an ABB RAPID MOD File"
};
// Show the Dialog.
// If the user clicked OK in the dialog and
// a .MOD file was selected, open it.
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Assign the cursor in the Stream to the Form's Cursor property.
//this.Cursor = new Cursor(openFileDialog1.OpenFile());
using (StreamReader sr = new StreamReader(openFileDialog1.FileName))
{
// define a regular expression to search for extr calls
Regex Extr_Ex = new Regex(@"\bExtr\(-?\d*.\d*\);", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
Regex MoveL_Ex = new Regex(@"\bMoveL\s+(.*)(z\d.*)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
Match MoveLString = null;
while (sr.Peek() >= 0)
{
CurrLine = sr.ReadLine();
//Console.WriteLine(sr.ReadLine());
// check if the line is a match
if (Extr_Ex.IsMatch(CurrLine))
{
// Keep a count for total matches
MatchCount++;
// Save extr calls in a string
ExtCode_1 += NewLine + TAB + TAB + Extr_Ex.Match(CurrLine).ToString();
// Read next line (always a MoveL) to get Pos data for TriggL
NextLine = sr.ReadLine();
//Console.WriteLine(NextLine);
if (MoveL_Ex.IsMatch(NextLine))
{
// Next Line contains MoveL
// get matched string
MoveLString = MoveL_Ex.Match(NextLine);
GroupCollection group = MoveLString.Groups;
MoveL_Pos_Data = group[1].Value.ToString();
MoveL_Ref_Data = group[2].Value.ToString();
MoveLFull = MoveL_Pos_Data + MoveL_Ref_Data;
}
// replace Extr with follwing commands
ModCode += NewLine + TAB + TAB + "TriggL " + MoveL_Pos_Data + "extr," + MoveL_Ref_Data;
ModCode += NewLine + TAB + TAB + "WaitDI DI1_1,1;";
ModCode += NewLine + TAB + TAB + "MoveL " + MoveLFull;
ModCode += NewLine + TAB + TAB + "Reset DO1_1;";
//break;
}
else
{
// No extr Match
ModCode += "\r\n" + CurrLine;
}
}
Console.WriteLine($"Total Matches: {MatchCount}");
}
}
// Write modified code into a new output file
string SaveDirectoryPath = Path.GetDirectoryName(openFileDialog1.FileName);
string ModName = Path.GetFileNameWithoutExtension(openFileDialog1.FileName);
SavePath = SaveDirectoryPath + @"\" + ModName + "_rev.mod";
File.WriteAllText(SavePath, ModCode);
//Write Extr matches into new output file
//Prepare module
ExtCallMod = "MODULE ExtruderCalls";
// All extr calls in one routine
//Prepare routines
ExtCallMod += NewLine + NewLine + TAB + "PROC Prg_ExtCall"; // + 1;
ExtCallMod += ExtCode_1;
ExtCallMod += NewLine + NewLine + TAB + "ENDPROC";
ExtCallMod += NewLine + NewLine;
//}
ExtCallMod += "ENDMODULE";
// Write to file
string ExtCallSavePath = SaveDirectoryPath + @"\ExtrCalls.mod";
File.WriteAllText(ExtCallSavePath, ExtCallMod);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
Хотя это помогает мне достичь того, чего я хочу, процесс идет очень медленно.Поскольку я новичок в программировании на C #, я подозреваю, что медлительность происходит из-за дублирования исходного содержимого файла в строку и НЕ заменяет содержимое на месте (я не уверен, можно ли напрямую заменить содержимое в исходном файле).Для входного файла из 20000 строк весь процесс занимает чуть более 5 минут.
Раньше я получал следующую ошибку: Сообщение = Помощник по управляемой отладке 'ContextSwitchDeadlock': 'CLR не удалось перейти из контекста COM 0xb27138 в контекст COM 0xb27080 в течение 60 секунд. Поток, которому принадлежит целевой контекст / квартира, скорее всего, либо делает ожидание без перекачки, либо обрабатывает очень длительную операцию без перекачки сообщений Windows.Эта ситуация, как правило, оказывает негативное влияние на производительность и может даже привести к тому, что приложение перестает отвечать на запросы или использование памяти постоянно увеличивается с течением времени.Чтобы избежать этой проблемы, все потоки однопотоковых квартир (STA) должны использовать примитивы перекачки (такие как CoWaitForMultipleHandles) и регулярно перекачивать сообщения во время длительных операций. '
Мне удалось обойти это, отключив' ContextSwitchDeadlockНастройки в настройках отладчика.Это не может быть лучшей практикой.
Может ли кто-нибудь помочь мне улучшить производительность моего кода?
РЕДАКТИРОВАТЬ : Я обнаружил, что контроллер робота имеет ограничения по количеству строк, которые должны быть в файле MOD (выходной файл).Максимально допустимое количество строк - 32768. Я придумал логику для разделения содержимого построителя строк на отдельные выходные файлы следующим образом:
// Split modCodeBuilder into seperate strings based on final size
const int maxSize = 32500;
string result = modCodeBuilder.ToString();
string[] splitResult = result.Split(new string[] { "\r\n" }, StringSplitOptions.None);
string[] splitModCode = new string[maxSize];
// Setup destination directory to be same as source directory
string destDir = Path.GetDirectoryName(fileNames[0]);
for (int count = 0; ; count++)
{
// Get the next batch of text by skipping the amount
// we've taken so far and then taking the maxSize.
string modName = $"PrgMOD_{count + 1}";
string procName = $"Prg_{count + 1}()";
// Use Array Copy to extract first 32500 lines from modCode[]
int src_start_index = count * maxSize;
int srcUpperLimit = splitResult.GetUpperBound(0);
int dataLength = maxSize;
if (src_start_index > srcUpperLimit) break; // Exit loop when there's no text left to take
if (src_start_index > 1)
{
// Make sure calculate right length so that src index is not exceeded
dataLength = srcUpperLimit - maxSize;
}
Array.Copy(splitResult, src_start_index, splitModCode, 0, dataLength);
string finalModCode = String.Join("\r\n", splitModCode);
string batch = String.Concat("MODULE ", modName, "\r\n\r\n\tPROC ", procName, "\r\n", finalModCode, "\r\n\r\n\tENDPROC\r\n\r\nENDMODULE");
//if (batch.Length == 0) break;
// Generate file name based on count
string fileName = $"ABB_R3DP_{count + 1}.mod";
// Write our file text
File.WriteAllText(Path.Combine(destDir, fileName), batch);
// Write status to output textbox
TxtOutput.AppendText("\r\n");
TxtOutput.AppendText("\r\n");
TxtOutput.AppendText($"Modified MOD File: {fileName} is generated sucessfully! It is saved to location: {Path.Combine(destDir, fileName)}");
}