C#非常实用的技巧
1、解压和压缩
.NET Framework 4.5以上版本:
string zipFilePath = @"C:\path\to\file.zip";
string destFolder = @"C:\path\to\destination\folder";
using (var archive = ZipFile.OpenRead(zipFilePath))
{
foreach (var entry in archive.Entries)
{
// 如果是文件,则解压到指定目录
if (!entry.FullName.EndsWith("/"))
{
string destinationPath = Path.Combine(destFolder, entry.FullName);
entry.ExtractToFile(destinationPath, true);
}
// 如果是文件夹,则创建对应目录
else
{
Directory.CreateDirectory(Path.Combine(destFolder, entry.FullName));
}
}
}
.NET Framework 4以下
虽然微软的net提供了很多解压和压缩的程序,但是如果你的系统是net Framework4,那上面的代码就用不了了,此时需要借用7za.exe
1.0 C# 解压文件
//放置7z的路径
string Zip7FileName = Path.Combine("D:\\Project", "7za.exe");
var tarArgs = string.Format("x \"{0}\" -o\"{1}\" -y", "待解压路径", "输出路径");
using (var process = new Process())
{
process.StartInfo.FileName = Zip7FileName;
process.StartInfo.Arguments = tarArgs;
process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
process.Start();
process.WaitForExit();
}
解压解释:
var tarArgs = string.Format("x \"{0}\" -o\"{1}\" -y", "待解压路径", "输出路径");
-y
参数表示 "yes to all",即自动回答 "yes",也就是在出现任何提示时都自动选择 "是"。这意味着7z
命令行工具不会询问用户是否覆盖已有的文件、创建缺失的目录等等,而是直接按照默认行为执行。例如,在以下语句中
-y
参数告诉7z
命令行工具在解压缩文件时自动覆盖目标文件夹中已有的同名文件。csharpCopy Code
var tarArgs = string.Format("x \"{0}\" -o\"{1}\" -y", "待解压路径", "输出路径");
-o
参数表示 "output directory",即指定解压缩后的文件输出目录。在7z
命令行工具中,可以使用-o
参数来指定输出目录的路径。例如,在以上语句中,-o"{1}"
参数将解压缩后的文件输出到名为importzipedFolder
的目录中。需要注意的是,
7z
命令行工具只能解压缩一些特定的文件格式,例如.zip
,.tar
,.gz
,.bz2
等等。如果需要解压缩其它类型的文件,可能需要使用相应的解压缩工具,并根据相应工具的使用方法来编写代码。
1.1 C# 压缩文件
//选择保存压缩包的的位置(此处以C:\Program Files (x86)\001.tar为例)
string zipFilePath = "C:\Program Files (x86)\001.tar";
StringBuilder tarArgs = new StringBuilder($"a -ttar \"{zipFilePath}\"");
//需要压缩的文件夹
DirectoryInfo dirInfo = new DirectoryInfo(Path.Combine(exportzipedFolder));
foreach (var subDir in dirInfo.GetDirectories())
{
tarArgs.Append(" \"").Append(subDir.FullName).Append("\"");
}
using (var process = new Process())
{
process.StartInfo.FileName = Zip7FileName;
process.StartInfo.Arguments = tarArgs.ToString();
process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit();
}
if (Directory.Exists(exportzipedFolder))
{
Directory.Delete(exportzipedFolder, true);
}
2 按位读取二进制
2.0 C#读取二进制
string filePath = "C:\Program Files (x86)\001.bin";
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
using (var reader = new BinaryReader(fs, Encoding.Default))
{
//此处需要知道,需要读取多少位、用什么类型读取
var readType =Type;
object countent = new object();
switch (readType)
{
case Hmi.DataType.UInt16:
countent = reader.ReadUInt16();
break;
case Hmi.DataType.Int16:
countent = reader.ReadInt16();
break;
case Hmi.DataType.UInt32:
countent = reader.ReadUInt32();
break;
case Hmi.DataType.Int32:
countent = reader.ReadInt32();
break;
case Hmi.DataType.BCD16:
countent = reader.ReadUInt16();
break;
case Hmi.DataType.BCD32:
countent = reader.ReadInt32();
break;
case Hmi.DataType.Single:
countent = reader.ReadSingle();
break;
case Hmi.DataType.Double:
countent = reader.ReadDouble();
break;
case Hmi.DataType.String:
byte[] data = new byte[recipeDataType[i].StringLength];
int bytesRead = reader.Read(data, 0, data.Length);
string result = Encoding.Default.GetString(data, 0, bytesRead);
int byteCount = Encoding.Default.GetByteCount(result);
fs.Seek(byteCount, SeekOrigin.Current);
string str = string.Join("", result).TrimEnd('\0');
countent = str;
break;
case Hmi.DataType.Hex16:
countent = reader.ReadUInt16();
break;
case Hmi.DataType.Hex32:
countent = reader.ReadUInt16();
break;
case Hmi.DataType.Binary16:
countent = reader.ReadUInt16();
break;
case Hmi.DataType.Binary32:
countent = reader.ReadUInt16();
break;
case Hmi.DataType.UInt64:
countent = reader.ReadUInt64();
break;
case Hmi.DataType.Int64:
countent = reader.ReadInt64();
break;
case Hmi.DataType.Bool:
countent = reader.ReadInt16();
break;
default:
break;
}
}
}
代码解释:读取二进制的时候,需要注意中文的读取方式,即类型中的string类型,如果需要读取18个字节,但是中文只有三个(UTF8编码中,中文占用3个字节,用Encoding.Default读取,默认使用的是GB2312编码,一个中文占用2个字节,ASCII码中一个中文也是占用2个字节)按照GB2312读取,实际只能读取到6个字节,此时18个字节是浪费掉的,此时需要使用调用fs.Seek(byteCount, SeekOrigin.Current);将文件流的当前位置移动指定的字节数;读取二进制还需要额外注意的类似的bool类型,bool类型在编程语言中是True和False,但是在二进制下只有1和0
2.0 C#写二进制
string filePath = "C:\Program Files (x86)\001.bin";
using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
{
using (BinaryWriter writer = new BinaryWriter(fileStream, Encoding.Default))
{
string content =String.Empty;
//此处需要知道,需要读取多少位、用什么类型读取
var readType = Type;
switch (readType)
{
case DataType.UInt16:
writer.Write(Convert.ToUInt16(content));
break;
case DataType.Int16:
writer.Write(Convert.ToUInt16(content));
break;
case DataType.UInt32:
writer.Write(Convert.ToUInt32(content));
break;
case DataType.Int32:
writer.Write(Convert.ToInt32(content));
break;
case DataType.BCD16:
writer.Write(Convert.ToUInt16(content));
break;
case DataType.BCD32:
writer.Write(Convert.ToInt32(content));
break;
case DataType.Single:
writer.Write(Convert.ToSingle(content));
break;
case DataType.Double:
writer.Write(Convert.ToDouble(content));
break;
case DataType.String:
//string类型需要处理需要读取多少位
int byteCount =100;
byte[] buffer = Encoding.Default.GetBytes(content);
if (buffer.Length < byteCount)
{
byte[] paddedBytes = new byte[byteCount];
Buffer.BlockCopy(buffer, 0, paddedBytes, 0, buffer.Length);
buffer = paddedBytes;
}
writer.Write(buffer, 0, byteCount);
fileStream.Seek(byteCount, SeekOrigin.Current);
break;
case DataType.Hex16:
writer.Write(Convert.ToUInt16(content));
break;
case DataType.Hex32:
writer.Write(Convert.ToUInt16(content));
break;
case DataType.Binary16:
writer.Write(Convert.ToUInt16(content));
break;
case DataType.Binary32:
writer.Write(Convert.ToUInt16(content));
break;
case DataType.UInt64:
writer.Write(Convert.ToUInt64(content));
break;
case DataType.Int64:
writer.Write(Convert.ToInt64(content));
break;
case DataType.Bool:
writer.Write(Convert.ToInt16(content));
break;
default:
break;
}
}
}
和读二进制类型,写二进制依旧主要注意编码方式、读取的字节类型。以上代码能帮助我们读取二进制,但是请注意,我们读取的仅仅是某些位的数据,实际的二进制是长这样的:
实际上,我们上面代码,仅仅读取了二进制文件39,用UTF-7(推荐使用UTF-7)编码GB2123读取出来的是57,没错,这么多00 01 02加那么多代码仅读取了一个57,后面的怎么读,可能需要根据实际情况进行考虑。
3、MQTT发布订阅
using System;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
public class MqttClient
{
private IMqttClient mqttClient;
public async Task ConnectAsync(string brokerIp, int brokerPort, string username, string password)
{
var factory = new MqttFactory();
mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer(brokerIp, brokerPort)
.WithCredentials(username, password)
.WithClientId("mqtt-client")
.WithCleanSession()
.Build();
await mqttClient.ConnectAsync(options);
}
public void Disconnect()
{
if (mqttClient != null && mqttClient.IsConnected)
{
mqttClient.DisconnectAsync().Wait();
mqttClient.Dispose();
mqttClient = null;
}
}
public async Task PublishAsync(string topic, string payload)
{
if (mqttClient == null || !mqttClient.IsConnected)
{
throw new InvalidOperationException("MQTT client is not connected.");
}
var message = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(payload)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
.Build();
await mqttClient.PublishAsync(message);
}
public async Task SubscribeAsync(string topic, Action<MqttApplicationMessageReceivedEventArgs> handler)
{
if (mqttClient == null || !mqttClient.IsConnected)
{
throw new InvalidOperationException("MQTT client is not connected.");
}
await mqttClient.SubscribeAsync(new TopicFilterBuilder()
.WithTopic(topic)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
.Build());
mqttClient.UseApplicationMessageReceivedHandler(handler);
}
public async Task UnsubscribeAsync(string topic)
{
if (mqttClient == null || !mqttClient.IsConnected)
{
throw new InvalidOperationException("MQTT client is not connected.");
}
await mqttClient.UnsubscribeAsync(topic);
}
}
低版本可能需要做一个兼容:
private void Subscribe_ClickAsync(object sender, RoutedEventArgs e)
{
try
{
if (mqttClient == null || !mqttClient.IsConnected)
{
throw new InvalidOperationException("MQTT client is not connected.");
}
mqttClient.SubscribeAsync(new MqttTopicFilterBuilder()
.WithTopic(txt_topic.Text)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
.Build());
mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync1;
}
catch (Exception ex)
{
MessageBox.Show("系统异常:" + ex.Message);
}
}
StringBuilder StringBuilder = new StringBuilder();
private async Task MqttClient_ApplicationMessageReceivedAsync1(MqttApplicationMessageReceivedEventArgs arg)
{
try
{
this.Dispatcher.Invoke(new Action(delegate
{
byte[] buffer = arg.ApplicationMessage.Payload;
string result = Encoding.Default.GetString(buffer, 0, buffer.Length);
StringBuilder.Append($"接受到:{result}\n");
txt_read.Text = StringBuilder.ToString();
}));
}
catch (Exception ex)
{
MessageBox.Show("系统异常:" + ex.Message);
}
}
private void Publish_ClickAsync(object sender, RoutedEventArgs e)
{
try
{
if (mqttClient == null || !mqttClient.IsConnected)
{
throw new InvalidOperationException("MQTT client is not connected.");
}
byte[] payload = Encoding.Default.GetBytes(txt_writ.Text);
var message = new MqttApplicationMessageBuilder()
.WithTopic(txt_topic.Text)
.WithPayload(payload)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
.Build();
mqttClient.PublishAsync(message);
txt_read.Text = StringBuilder.ToString();
}
catch (Exception ex)
{
MessageBox.Show("系统异常:" + ex.Message);
}
}