当前位置: 首页 > news >正文

【.Net实用方法总结】 整理并总结System.IO中BufferedStream类及其方法介绍

🐋作者简介:博主是一位.Net开发者,同时也是RPA和低代码平台的践行者。
🐬个人主页:会敲键盘的肘子
🐰系列专栏:.Net实用方法总结
🦀专栏简介:博主针对.Net开发和C站问答过程中遇到的问题进行总结,形成本专栏,希望可以帮助到您解决问题。
🐶座右铭:总有一天你所坚持的会反过来拥抱你。


在这里插入图片描述

🌈写在前面:

本文主要介绍System.IO命名空间的BufferedStream 类,介绍其常用的方法和示例说明。


👉本文关键字:System.IO、BufferedStream类、方法示例、C#

文章目录

      • 1️⃣ System.IO命名空间
      • 2️⃣ BufferedStream类
        • ♈ 定义
        • ♉ 示例
        • ♉ 构造函数
          • BufferedStream(Stream) 使用默认的缓冲区大小 4096 字节初始化 BufferedStream 类的新实例
          • BufferedStream(Stream, Int32) 使用指定的缓冲区大小初始化 BufferedStream 类的新实例
        • ♊ 属性
          • BufferSize 获取此缓冲流的缓冲区大小(以字节为单位)
          • CanRead 获取一个值,该值指示当前流是否支持读取
          • CanWrite 获取一个值,该值指示当前流是否支持写入
          • Length 获取流长度,长度以字节为单位
        • ♌ 常用方法
          • Close() 关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)
          • CopyTo(Stream) 从当前流中读取字节并将其写入到另一流中
          • CopyTo(Stream, Int32) 使用指定的缓冲区大小,从当前流中读取字节并将其写入到另一流中
          • CopyToAsync(Stream) 从当前流中异步读取字节并将其写入到另一个流中
          • Dispose() 释放由 Stream 使用的所有资源
          • Read(Byte[], Int32, Int32) 将字节从当前缓冲流复制到数组
          • ReadAsync(Byte[], Int32, Int32) 从当前流异步读取字节序列,并将流中的位置提升读取的字节数
          • ReadByte() 从基础流中读取一个字节,并返回转换为 `int` 的该字节;或者如果从流的末尾读取则返回 -1
          • Write(Byte[], Int32, Int32) 将字节复制到缓冲流,并将缓冲流内的当前位置前进写入的字节数
          • WriteAsync(Byte[], Int32, Int32) 将字节序列异步写入当前流,并将流的当前位置提升写入的字节数
          • WriteByte(Byte) 一个字节写入文件流中的当前位置
          • Flush() 清除此流的缓冲区,使得所有缓冲数据都写入到文件中
          • FlushAsync() 异步清除此流的所有缓冲区并导致所有缓冲数据都写入基础设备中
        • ♍ 注解
        • ♎ 更多方法

1️⃣ System.IO命名空间

.NET中的IO操作命名空间,包含允许读写文件数据流的类型以及提供基本文件和目录支持的类型。

我们在.NET中的IO操作,经常需要调用一下几个类。

  • FileStream类

​ 文件流类,负责大文件的拷贝,读写。

  • Path类

​ Path类中方法,基本都是对字符串(文件名)的操作,与实际文件没多大关系。

  • File类

    File类可以进行一些对小文件拷贝、剪切操作,还能读一些文档文件。

  • Dirctory类

    目录操作,创建文件、删除目录,获取目录下文件名等等。

2️⃣ BufferedStream类

♈ 定义

将缓冲层添加到另一个流上的读取和写入操作。 此类不能被继承。

public sealed class BufferedStream : System.IO.Stream

♉ 示例

下面的代码示例演示如何使用 BufferedStream 类来 NetworkStream 增加某些 I/O 操作的性能。 在启动客户端之前,"开始"菜单远程计算机上的服务器。 启动客户端时,将远程计算机名称指定为命令行参数。 dataArraySize更改常streamBufferSize量以查看它们对性能的影响。

第一个示例演示在客户端上运行的代码,第二个示例显示服务器上运行的代码。

示例 1:在客户端上运行的代码

using System;
using System.IO;
using System.Globalization;
using System.Net;
using System.Net.Sockets;

public class Client
{
    const int dataArraySize    =   100;
    const int streamBufferSize =  1000;
    const int numberOfLoops    = 10000;

    static void Main(string[] args)
    {
        // Check that an argument was specified when the
        // program was invoked.
        if(args.Length == 0)
        {
            Console.WriteLine("Error: The name of the host computer" +
                " must be specified when the program is invoked.");
            return;
        }

        string remoteName = args[0];

        // Create the underlying socket and connect to the server.
        Socket clientSocket = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);

        clientSocket.Connect(new IPEndPoint(
            Dns.Resolve(remoteName).AddressList[0], 1800));

        Console.WriteLine("Client is connected.\n");

        // Create a NetworkStream that owns clientSocket and
        // then create a BufferedStream on top of the NetworkStream.
        // Both streams are disposed when execution exits the
        // using statement.
        using(Stream
            netStream = new NetworkStream(clientSocket, true),
            bufStream =
                  new BufferedStream(netStream, streamBufferSize))
        {
            // Check whether the underlying stream supports seeking.
            Console.WriteLine("NetworkStream {0} seeking.\n",
                bufStream.CanSeek ? "supports" : "does not support");

            // Send and receive data.
            if(bufStream.CanWrite)
            {
                SendData(netStream, bufStream);
            }
            if(bufStream.CanRead)
            {
                ReceiveData(netStream, bufStream);
            }

            // When bufStream is closed, netStream is in turn
            // closed, which in turn shuts down the connection
            // and closes clientSocket.
            Console.WriteLine("\nShutting down the connection.");
            bufStream.Close();
        }
    }

    static void SendData(Stream netStream, Stream bufStream)
    {
        DateTime startTime;
        double networkTime, bufferedTime;

        // Create random data to send to the server.
        byte[] dataToSend = new byte[dataArraySize];
        new Random().NextBytes(dataToSend);

        // Send the data using the NetworkStream.
        Console.WriteLine("Sending data using NetworkStream.");
        startTime = DateTime.Now;
        for(int i = 0; i < numberOfLoops; i++)
        {
            netStream.Write(dataToSend, 0, dataToSend.Length);
        }
        networkTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes sent in {1} seconds.\n",
            numberOfLoops * dataToSend.Length,
            networkTime.ToString("F1"));

        // Send the data using the BufferedStream.
        Console.WriteLine("Sending data using BufferedStream.");
        startTime = DateTime.Now;
        for(int i = 0; i < numberOfLoops; i++)
        {
            bufStream.Write(dataToSend, 0, dataToSend.Length);
        }
        bufStream.Flush();
        bufferedTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes sent in {1} seconds.\n",
            numberOfLoops * dataToSend.Length,
            bufferedTime.ToString("F1"));

        // Print the ratio of write times.
        Console.WriteLine("Sending data using the buffered " +
            "network stream was {0} {1} than using the network " +
            "stream alone.\n",
            (networkTime/bufferedTime).ToString("P0"),
            bufferedTime < networkTime ? "faster" : "slower");
    }

    static void ReceiveData(Stream netStream, Stream bufStream)
    {
        DateTime startTime;
        double networkTime, bufferedTime = 0;
        int bytesReceived = 0;
        byte[] receivedData = new byte[dataArraySize];

        // Receive data using the NetworkStream.
        Console.WriteLine("Receiving data using NetworkStream.");
        startTime = DateTime.Now;
        while(bytesReceived < numberOfLoops * receivedData.Length)
        {
            bytesReceived += netStream.Read(
                receivedData, 0, receivedData.Length);
        }
        networkTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes received in {1} seconds.\n",
            bytesReceived.ToString(),
            networkTime.ToString("F1"));

        // Receive data using the BufferedStream.
        Console.WriteLine("Receiving data using BufferedStream.");
        bytesReceived = 0;
        startTime = DateTime.Now;

        int numBytesToRead = receivedData.Length;

        while (numBytesToRead > 0)
        {
            // Read may return anything from 0 to numBytesToRead.
            int n = bufStream.Read(receivedData,0, receivedData.Length);
            // The end of the file is reached.
            if (n == 0)
                break;
            bytesReceived += n;
            numBytesToRead -= n;
        }

        bufferedTime = (DateTime.Now - startTime).TotalSeconds;
        Console.WriteLine("{0} bytes received in {1} seconds.\n",
            bytesReceived.ToString(),
            bufferedTime.ToString("F1"));

        // Print the ratio of read times.
        Console.WriteLine("Receiving data using the buffered network" +
            " stream was {0} {1} than using the network stream alone.",
            (networkTime/bufferedTime).ToString("P0"),
            bufferedTime < networkTime ? "faster" : "slower");
    }
}

示例 2:在服务器上运行的代码

using System;
using System.Net;
using System.Net.Sockets;

public class Server
{
    static void Main()
    {
        // This is a Windows Sockets 2 error code.
        const int WSAETIMEDOUT = 10060;

        Socket serverSocket;
        int bytesReceived, totalReceived = 0;
        byte[] receivedData = new byte[2000000];

        // Create random data to send to the client.
        byte[] dataToSend = new byte[2000000];
        new Random().NextBytes(dataToSend);

        IPAddress ipAddress =
            Dns.Resolve(Dns.GetHostName()).AddressList[0];

        IPEndPoint ipEndpoint = new IPEndPoint(ipAddress, 1800);

        // Create a socket and listen for incoming connections.
        using(Socket listenSocket = new Socket(
            AddressFamily.InterNetwork, SocketType.Stream,
            ProtocolType.Tcp))
        {
            listenSocket.Bind(ipEndpoint);
            listenSocket.Listen(1);

            // Accept a connection and create a socket to handle it.
            serverSocket = listenSocket.Accept();
            Console.WriteLine("Server is connected.\n");
        }

        try
        {
            // Send data to the client.
            Console.Write("Sending data ... ");
            int bytesSent = serverSocket.Send(
                dataToSend, 0, dataToSend.Length, SocketFlags.None);
            Console.WriteLine("{0} bytes sent.\n",
                bytesSent.ToString());

            // Set the timeout for receiving data to 2 seconds.
            serverSocket.SetSocketOption(SocketOptionLevel.Socket,
                SocketOptionName.ReceiveTimeout, 2000);

            // Receive data from the client.
            Console.Write("Receiving data ... ");
            try
            {
                do
                {
                    bytesReceived = serverSocket.Receive(receivedData,
                        0, receivedData.Length, SocketFlags.None);
                    totalReceived += bytesReceived;
                }
                while(bytesReceived != 0);
            }
            catch(SocketException e)
            {
                if(e.ErrorCode == WSAETIMEDOUT)
                {
                    // Data was not received within the given time.
                    // Assume that the transmission has ended.
                }
                else
                {
                    Console.WriteLine("{0}: {1}\n",
                        e.GetType().Name, e.Message);
                }
            }
            finally
            {
                Console.WriteLine("{0} bytes received.\n",
                    totalReceived.ToString());
            }
        }
        finally
        {
            serverSocket.Shutdown(SocketShutdown.Both);
            Console.WriteLine("Connection shut down.");
            serverSocket.Close();
        }
    }
}

♉ 构造函数

BufferedStream(Stream) 使用默认的缓冲区大小 4096 字节初始化 BufferedStream 类的新实例
public BufferedStream (System.IO.Stream stream);

参数

stream

Stream

当前流。

首次使用此构造函数初始化对象时 BufferedStream 分配共享读/写缓冲区。 如果所有读取和写入大于或等于 bufferSize,则不使用共享缓冲区。

BufferedStream(Stream, Int32) 使用指定的缓冲区大小初始化 BufferedStream 类的新实例
public BufferedStream (System.IO.Stream stream, int bufferSize);

参数

stream

Stream

当前流。

bufferSize

Int32

缓冲区大小(以字节为单位)。

示例

此代码示例是为 BufferedStream 类提供的一个更大示例的一部分。

// Create a NetworkStream that owns clientSocket and
// then create a BufferedStream on top of the NetworkStream.
// Both streams are disposed when execution exits the
// using statement.
using(Stream
    netStream = new NetworkStream(clientSocket, true),
    bufStream =
          new BufferedStream(netStream, streamBufferSize))

♊ 属性

BufferSize 获取此缓冲流的缓冲区大小(以字节为单位)
public int BufferSize { get; }
CanRead 获取一个值,该值指示当前流是否支持读取
public override bool CanRead { get; }

示例

此代码示例是为 BufferedStream 类提供的一个更大示例的一部分。

if(bufStream.CanRead)
{
    ReceiveData(netStream, bufStream);
}
CanWrite 获取一个值,该值指示当前流是否支持写入
public override bool CanWrite { get; }

示例

此代码示例是为 BufferedStream 类提供的一个更大示例的一部分。

if(bufStream.CanWrite)
{
    SendData(netStream, bufStream);
}
Length 获取流长度,长度以字节为单位
public override long Length { get; }

♌ 常用方法

Close() 关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)
public virtual void Close ();

注意:此方法调用 Dispose ,指定 true 以释放所有资源。 不需要专门调用 Close 方法。 请确保 Stream 已正确释放每个对象。 可以 Stream using Using 在 Visual Basic) 中 (或块中声明对象,以确保释放流及其所有资源,或者可以显式调用 Dispose 方法。

CopyTo(Stream) 从当前流中读取字节并将其写入到另一流中
public void CopyTo (System.IO.Stream destination);

参数

destination

Stream

当前流的内容将复制到的流。

示例

下面的示例将的内容复制 FileStream 到 MemoryStream 中。

// Create the streams.
MemoryStream destination = new MemoryStream();

using (FileStream source = File.Open(@"c:\temp\data.dat",
    FileMode.Open))
{

    Console.WriteLine("Source length: {0}", source.Length.ToString());

    // Copy source to destination.
    source.CopyTo(destination);
}

Console.WriteLine("Destination length: {0}", destination.Length.ToString());
CopyTo(Stream, Int32) 使用指定的缓冲区大小,从当前流中读取字节并将其写入到另一流中
public virtual void CopyTo (System.IO.Stream destination, int bufferSize);

参数

destination

Stream

当前流的内容将复制到的流。

bufferSize

Int

缓冲区的大小。 此值必须大于零。 默认大小为 81920。

CopyToAsync(Stream) 从当前流中异步读取字节并将其写入到另一个流中
public System.Threading.Tasks.Task CopyToAsync (System.IO.Stream destination);

参数

destination

Stream

当前流的内容将复制到的流。

示例

下面的示例演示如何使用两个 FileStream 对象将文件从一个目录异步复制到另一个目录。 FileStream 类是从 Stream 类派生的。 请注意, Click 控件的事件处理程序 Button 使用修饰符标记, async 因为它调用异步方法

using System;
using System.Threading.Tasks;
using System.Windows;
using System.IO;

namespace WpfApplication
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            string StartDirectory = @"c:\Users\exampleuser\start";
            string EndDirectory = @"c:\Users\exampleuser\end";

            foreach (string filename in Directory.EnumerateFiles(StartDirectory))
            {
                using (FileStream SourceStream = File.Open(filename, FileMode.Open))
                {
                    using (FileStream DestinationStream = File.Create(EndDirectory + filename.Substring(filename.LastIndexOf('\\'))))
                    {
                        await SourceStream.CopyToAsync(DestinationStream);
                    }
                }
            }
        }
    }
}

CopyToAsync方法使你可以在不阻塞主线程的情况下执行占用大量资源的 i/o 操作。

Dispose() 释放由 Stream 使用的所有资源
public void Dispose ();
Read(Byte[], Int32, Int32) 将字节从当前缓冲流复制到数组
public override int Read (byte[] buffer, int offset, int count);

参数

buffer

Byte[]

将字节复制到的缓冲区。

offset

Int32

缓冲区中的字节偏移量,从此处开始读取字节。

count

Int32

要读取的字节数。

返回

Int32

读入 array 中的总字节数。 如果可用的字节没有所请求的那么多,总字节数可能小于请求的字节数;或者如果在可读取任何数据前就已到达流的末尾,则为零。

示例

此代码示例是为 BufferedStream 类提供的一个更大示例的一部分。

// Receive data using the BufferedStream.
Console.WriteLine("Receiving data using BufferedStream.");
bytesReceived = 0;
startTime = DateTime.Now;

int numBytesToRead = receivedData.Length;

while (numBytesToRead > 0)
{
    // Read may return anything from 0 to numBytesToRead.
    int n = bufStream.Read(receivedData,0, receivedData.Length);
    // The end of the file is reached.
    if (n == 0)
        break;
    bytesReceived += n;
    numBytesToRead -= n;
}

bufferedTime = (DateTime.Now - startTime).TotalSeconds;
Console.WriteLine("{0} bytes received in {1} seconds.\n",
    bytesReceived.ToString(),
    bufferedTime.ToString("F1"));

Read仅当到达流的末尾时,该方法才会返回 0。 在所有其他情况下, Read 始终在返回之前从流中读取至少一个字节。 根据定义,如果在调用 Read时流中没有可用数据,该方法 Read 将返回 0 (到达流的末尾会自动) 。 即使尚未到达流的末尾,实现也可以返回比请求的字节少。

用于 BinaryReader 读取基元数据类型。

ReadAsync(Byte[], Int32, Int32) 从当前流异步读取字节序列,并将流中的位置提升读取的字节数
public System.Threading.Tasks.Task<int> ReadAsync (byte[] buffer, int offset, int count);

参数

buffer

Byte[]

要写入数据的缓冲区。

offset

Int32

buffer 中的字节偏移量,从该偏移量开始写入从流中读取的数据。

count

Int32

最多读取的字节数。

返回

Task<Int32>

表示异步读取操作的任务。 TResult 参数的值包含读入缓冲区的总字节数。 如果当前可用字节数少于所请求的字节数,则该结果值可小于所请求的字节数;如果已到达流结尾时,则为 0(零)。

示例

下面的示例演示如何以异步方式从文件读取。 该示例使用 FileStream 类,该类派生自 Stream 类。

using System;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.IO;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            string filename = @"c:\Temp\userinputlog.txt";
            byte[] result;

            using (FileStream SourceStream = File.Open(filename, FileMode.Open))
            {
                result = new byte[SourceStream.Length];
                await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length);
            }

            UserInput.Text = System.Text.Encoding.ASCII.GetString(result);
        }
    }
}
ReadByte() 从基础流中读取一个字节,并返回转换为 int 的该字节;或者如果从流的末尾读取则返回 -1
public override int ReadByte ();

返回

Int32

强制转换为 Int32 的字节;或者如果已到达流的末尾,则为 -1。

Write(Byte[], Int32, Int32) 将字节复制到缓冲流,并将缓冲流内的当前位置前进写入的字节数
public override void Write (byte[] buffer, int offset, int count);

参数

buffer

Byte[]

字节数组,从该字节数组将 count 个字节复制到当前缓冲流中。

offset

Int32

缓冲区中的偏移量,从此处开始将字节复制到当前缓冲流中。

count

Int32

要写入当前缓冲流中的字节数。

示例

此代码示例是为 BufferedStream 类提供的一个更大示例的一部分。

// Send the data using the BufferedStream.
Console.WriteLine("Sending data using BufferedStream.");
startTime = DateTime.Now;
for(int i = 0; i < numberOfLoops; i++)
{
    bufStream.Write(dataToSend, 0, dataToSend.Length);
}
bufStream.Flush();
bufferedTime = (DateTime.Now - startTime).TotalSeconds;
Console.WriteLine("{0} bytes sent in {1} seconds.\n",
    numberOfLoops * dataToSend.Length,
    bufferedTime.ToString("F1"));
WriteAsync(Byte[], Int32, Int32) 将字节序列异步写入当前流,并将流的当前位置提升写入的字节数
public System.Threading.Tasks.Task WriteAsync (byte[] buffer, int offset, int count);

参数

buffer

Byte[]

从中写入数据的缓冲区。

offset

Int32

buffer 中的从零开始的字节偏移量,从此处开始将字节复制到该流。

count

Int32

最多写入的字节数。

返回

Task

表示异步写入操作的任务。

示例

下面的示例演示如何异步写入文件。 该示例使用 FileStream 类,该类派生自 Stream 类。

using System;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.IO;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            UnicodeEncoding uniencoding = new UnicodeEncoding();
            string filename = @"c:\Users\exampleuser\Documents\userinputlog.txt";

            byte[] result = uniencoding.GetBytes(UserInput.Text);

            using (FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate))
            {
                SourceStream.Seek(0, SeekOrigin.End);
                await SourceStream.WriteAsync(result, 0, result.Length);
            }
        }
    }
}
WriteByte(Byte) 一个字节写入文件流中的当前位置
public override void WriteByte (byte value);

参数

value

Byte

要写入流的字节。

Flush() 清除此流的缓冲区,使得所有缓冲数据都写入到文件中
public override void Flush ();

示例

此代码示例是为 BufferedStream 类提供的一个更大示例的一部分。

// Send the data using the BufferedStream.
Console.WriteLine("Sending data using BufferedStream.");
startTime = DateTime.Now;
for(int i = 0; i < numberOfLoops; i++)
{
    bufStream.Write(dataToSend, 0, dataToSend.Length);
}
bufStream.Flush();
bufferedTime = (DateTime.Now - startTime).TotalSeconds;
Console.WriteLine("{0} bytes sent in {1} seconds.\n",
    numberOfLoops * dataToSend.Length,
    bufferedTime.ToString("F1"));

除非显式调用或Close调用Flush流,否则刷新流不会刷新其基础编码器。

如果使用 BufferedStream 构造函数,因此在创建 BufferedStream 对象时指定缓冲区大小,则在内容达到缓冲区大小时会刷新。 例如,当缓冲区大小达到 5 字节时,例如 BufferedStream bs = new BufferedStream(bs, 5) 将刷新内容的代码。

自动维护缓冲区的所有读取和写入方法 BufferedStream ,因此在读取和写入之间来回切换时无需调用 Flush

FlushAsync() 异步清除此流的所有缓冲区并导致所有缓冲数据都写入基础设备中
public System.Threading.Tasks.Task FlushAsync ();

返回

Task

表示异步刷新操作的任务。

♍ 注解

缓冲区是内存中用于缓存数据的字节块,从而减少对操作系统的调用数。 缓冲区可提高读取和写入性能。 缓冲区可用于读取或写入,但不能同时两者。

BufferedStream 可以围绕某些类型的流组成。 它提供用于读取和写入基础数据源或存储库的字节的实现。 使用 BinaryReader 和 BinaryWriter 写入其他数据类型。 BufferedStream 旨在防止缓冲区在不需要缓冲区时减慢输入和输出速度。 如果始终读取和写入大于内部缓冲区大小的大小,则 BufferedStream 甚至可能不会分配内部缓冲区。 BufferedStream 此外,缓冲区在共享缓冲区中读取和写入。 假设你几乎总是执行一系列读取或写入操作,但很少在两个读取或写入之间交替。

♎ 更多方法

更多方法请查阅官方文档BufferedStream类。


⭐写在结尾:

文章中出现的任何错误请大家批评指出,一定及时修改。

希望写在这里的小伙伴能给个三连支持

相关文章:

  • Android移动应用开发之TextView实现阴影跑马灯文字效果
  • MySQL是怎样运行的:从根儿上理解MySQL | 查询优化器(二):基于规则的优化
  • 数据分享|WEKA用决策树、随机森林、支持向量机SVM、朴素贝叶斯、逻辑回归信贷违约预测报告
  • JavaSE学习----(八)常用类之Stirng类
  • 跨境电商自养号测评补单+广告结合打法,打造爆款产品
  • 01_中间件
  • 记录QUME上模拟ARM运行环境(内核 2.6.30)
  • JavaWeb开发之——MySQL数据模型(04)
  • c语言分层理解(c语言字符串+内存库函数)
  • Es6的promise和async
  • Java项目本地部署宝塔搭建实战java中小医院管理系统源码
  • java 低耦合观察者模式
  • 七、OCR-PaddlePaddle训练源码解析系列-文字识别
  • 数据结构与算法之非递归遍历二叉树
  • Unity技术手册 - 创建物体有几种方式?
  • ----------
  • 时间复杂度分析经典问题——最大子序列和
  • @angular/forms 源码解析之双向绑定
  • [笔记] php常见简单功能及函数
  • Angularjs之国际化
  • Debian下无root权限使用Python访问Oracle
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • mysql innodb 索引使用指南
  • Rancher-k8s加速安装文档
  • scrapy学习之路4(itemloder的使用)
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • Vue.js-Day01
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 飞驰在Mesos的涡轮引擎上
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 思考 CSS 架构
  • 一个完整Java Web项目背后的密码
  • Java数据解析之JSON
  • 组复制官方翻译九、Group Replication Technical Details
  • ​flutter 代码混淆
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • ​Java并发新构件之Exchanger
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (八)Flask之app.route装饰器函数的参数
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (一)RocketMQ初步认识
  • . Flume面试题
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .net 反编译_.net反编译的相关问题
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • ?
  • @基于大模型的旅游路线推荐方案
  • [C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测
  • [C++数据结构](31)哈夫曼树,哈夫曼编码与解码
  • [codeforces]Recover the String