C#中的文件操作

news2024/11/24 9:40:02

为什么要对文件进行操作?

在计算机当中,数据是二进制的形式存在的,文件则是用于存储这些数据的单位,因此在需要操作计算机中的数据时,需要对文件进行操作。

在程序开发过程中,操作变量和常量的时候,数据都是存储在内存中的,程序运行结束后会被全部删除。

所以当想要持续性保存相关数据时,就要通过文件或数据库的方式来对这些数据进行存储。

比如说,在游戏开发的过程中的背包存储物品、存档等操作都涉及很多相关的文件操作的部分,至于负责存储文件格式各有不同,比如Json、XML、BIN等都可以存储文件。

流与文件流

输入/输出流

大多数的应用程序都需要实现与设备之间的数据传输。
在C#当中将这种通过不同输入/输出设备之间的数据传输抽象表述为“流”,程序允许通过流的方式与输入/输出设备进行数据传输。
C#中的“流”都位于System.IO命名空间当中,称为IO(输入/输出)流、

文件流

计算机中,所有的文件都是以二进制方式存储的,因此C#专门针对文件的输入输出操作提供了一系列的流,统称为文件流。
文件流是程序中最常用的流,根据数据的传输方向可将其分为输入流和输出流。

常用的文件操作类

C#提供一系列文件操作类,来实现在程序运行时对文件进行创建、读写、移动等操作
大致可分为操作目录的类、操作文件的类、操作文件路径的类等。

操作文件的类

File
FileInfo
FileStream

操作目录的类

Directory
DirectoryInfo

操作文本文件的类

StreamReader
StreamWriter

操作文件路径的类。

Path

File类

File类是一个静态类,提供了很多静态方法,可以对文件进行创建、移动、查询和删除等操作。

  1. FileStream Create(string path)
    作用:根据传入的路径创建一个文件,如果文件不存在,则创建文件,如果存在且不是只读的,则覆盖其内容,否则报异常。
  2. void Delete(string path)
    作用:如果文件存在,则删除指定的文件,如果指定的文件不存在也不引发异常。
  3. bool Exists(string path)
    作用:判断指定文件是否存在,若存在则返回ture,否则返回false。
  4. void Move(string sourceFileName,string destFileName)
    作用:将指定的文件移动到新位置,可以在新位置为文件指定不同的名称。
  5. FileStream Open(string path,FileMode mode)
    作用:打开指定路径上的文件并返回FileStream对象。
  6. void Copy(string sourceFileName,string destFileName)
    作用:将现有的文件复制到新文件,可以指定是否允许覆盖同名的文件。
FileStream TextFile = File.Create("Data.txt");
TextFile.Close();//关闭文件流,后续对Data.txt文件操作就不会出现;文件Data.txt正由另一进程使用,因此该进程无法访问此文件

File.Create("Data.txt");
Console.WriteLine("文件创建成功");
if (File.Exists("Data.txt"))
{
     Console.WriteLine("创建成功");
}
else
{
     Console.WriteLine("创建失败");
}

File.Copy("Data.txt", @"E:\Data1.txt", true);//复制的同时可以改名称
File.Delete("Data.txt");
File.Move(@"E:\Data1.txt", @"D:\Data2.txt");//移动的同时可以改名称

文件路径的相关知识

  • / 表示当前文件(指运行程序的exe文件)的根目录
  • ./ 表示当前目录(指运行程序的exe文件所在位置),与Data.txt前没有任何符号等价
  • …/ 表示当前目录(指运行程序的exe文件所在位置)的上一级目录
  • 绝对路径是指文件在磁盘上的完整路径,在程序中使用绝对路径时需要注意该路径的位置,当该位置发生改变时可能会导致异常

FileInfo类

FileInfo类是实例类,所有的方法都只能在实例化对象后才能调用,创建FileInfo类对象时必须传递一个文件路径作为参数。
具体语法格式

FileInfo aFile = new FileInfo(@"E:\Data3.txt");

FileInfo类除了有许多与File类相似的方法(如:Create、Delete、Exists、MoveTo、CopyTo、Open)外,还有其特有的属性

  1. Directory
    表示当前文件所在的目录。
  2. DirectoryName
    该属性用于返回文件目录,而且这个属性是只读的,获取结果与Directory属性一样
  3. IsReadOnly
    该属性用于判断文件是否是只读的。
  4. Length
    该属性用于获取文件的大小(以字节为单位),并返回long值。
  5. FullName
    获取带路径的文件名
  6. CreationTime
    获取文件的创建时间
FileInfo aFile = new FileInfo(@"E:\Data3.txt");
aFile.Create();//创建文件
Console.WriteLine("文件创建成功");
Console.WriteLine(aFile.FullName);
 if (aFile.Exists)//判断文件是否存在,在此Exists为属性,而File类中为方法
 {
         Console.WriteLine("Data.txt文件存在");
 }
 else
 {
         Console.WriteLine("Data.txt文件不存在");
 }
 Console.WriteLine("文件当前目录为:"+aFile.Directory);
 Console.WriteLine("文件大小为:"+aFile.Length);

Directory类

Directory类是静态类,提供了许多静态方法用于对目录进行操作,例如创建、删除、查询和移动目录等

  1. DirectoryInfo CreateDirectory(string path)
    作用:创建指定路径的所有目录和子目录
  2. void Delete(string path)
    作用:删除指定路径的空目录
  3. bool Exists(string path)
    作用:判断指定路径目录是否存在,若存在则返回ture,否则返回false。
  4. DirectoryInfo GetParent(string path)
    作用:查找指定路径的父目录,包括相对路径和绝对路径
  5. void Move(string sourceDirName,string destDirName)
    作用:将文件或目录及其内容移到新位置。注意:只能同一磁盘下移动
 Directory.CreateDirectory(@"E:\cc\ss\1");
if (Directory.Exists(@"E:\cc\ss\1"))
{
     Console.WriteLine("目录存在");
}
else
{
      Console.WriteLine("目录不存在");
}
File.Create(@"E:\cc\ss\1\data.txt");
File.Delete(@"E:\cc\ss\1\data.txt");
Directory.Delete(@"E:\cc\ss\1");//删除没有内容的目录
Directory.Move(@"E:\cc", @"E:\tt");
注意在移动的时候,tt不能事先存在,并且只能在同一盘符中移动

DirectoryInfo类

DirectoryInfo类同样与Directory类相似,不同的是DirectoryInfo是一个实例类,该类不仅拥有与Directory功能类似的方法还有一些特殊的属性。

  1. Parent
    作用:获取指定子目录的父目录
  2. Root
    作用:获取路径的根目录
  3. Name
    作用:获取当前DirectoryInfo对象(所在目录)的名称
  4. Exists
    作用:判断指定目录是否存在
 DirectoryInfo di = new DirectoryInfo(@"E:\根目录\父级目录\当前目录");
 di.Create();
 Console.WriteLine("当前目录名称为:" + di.Name);
 Console.WriteLine("父目录名为:" + di.Parent);
 Console.WriteLine("根目录为:" + di.Root);

FileStream类读取文件

FileStream介绍

FileStream类表示在磁盘或网络路径上指向文件的流,并提供了在文件中读写字节和字节数组的方法(FileStream类提供的方法操作的是字节数据),通过这些方法FileStream对象可以读取诸如图像、声音等文件,也就是说FileStream能够处理各种数据文件。
FileStream类有很多重载的构造方法,其中最常用的是带有三个参数的构造方法

FileStream(string path, FileMode mode, FileAccess access);

path:文件路径名
mode:表示如何打开或创建文件(有 FileMode.Append、FileMode.Create、FileMode.Open等)
access:用于确定FileStream对象访问文件的方式(有FileAccess.Read、FileAccess.ReadWrite、FileAccess.Write三种)

常用方法

  1. int ReadByte()
    作用:从文件中读取一个字节,并将读取位置提升一个字节
  2. void Flush()
    作用:清除此流的缓冲区,使得所有缓冲的数据都写入到文件中
  3. void WriteByte(byte value)
    作用:将一个字节写入文件流的当前位置
  4. void Write(byte[] array,int offset,int count)
    从缓冲区(字节数组)读取数据将字节块写入该流
  5. int Read(byte[] array,int offset,int count)
    从流中读取字节块并将该数据写入给定缓冲区(字节数组)中
  6. long Seek(long offset,SeekOrigin origin)
    将该流的当前位置设置为给定值。将流origin位置(为枚举值Begin、Current、End)移动offset字节

FileStream类读取文件

byte[] byteData = new byte[1024];
char[] charData = new char[1024];
//使用using关键字,当前文件流对象使用完毕后会自动释放资源,即相当于执行aFile.Close(); aFile.Dispose();
using (FileStream aFile = new FileStream("Data.txt", FileMode.Open))
{
//设置当前流为文件的开始位置,大多数情况下,当打开文件时,指针均指向文件的开始位置,所以一般无此句也行
aFile.Seek(0, SeekOrigin.Begin);
//从流中读取字节块到byteData数组中(从流中的0(当前)位置读取1024字节数据块到byteData数组中,文件中没有1024字节可读取,就为读取全部)
aFile.Read(byteData, 0, 1024);
}
//将字符数组和内部缓冲区中的字节解码为字符数组
Decoder d = Encoding.Default.GetDecoder();//得到一个解码器,该解码器用于将已编码的字节转换为字符序列
d.GetChars(byteData, 0, byteData.Length, charData, 0);
//输出解码后的字符串
Console.WriteLine(charData);
Console.ReadKey();

说明:当Data.txt文件的数据大于1024字节,则只能读取1024字节,如果想要读取更多字节数据,需要把程序中的1024改为更大的数值

FileStream类写入文件

FileStream类向文件中写入数据与读取数据的过程非常相似,不同的是,读取数据时使用的是Read()方法,而写入时使用的是Write()方法

byte[] byteData;
char[] charData;
try
{
  using (FileStream aFile = new FileStream("Data.txt", FileMode.Create))
{
  //写一段字符串并使用ToCharArray()方法转换为字符存储到字符数组中
   charData = "Hello world by C#".ToCharArray();
   byteData = new byte[charData.Length];//实例化一个字节数组,长度与字符数组一样
//使用Encoder类实现将字符数组转为字节数组
    Encoder e = Encoding.Default.GetEncoder();//获得一个解码器,该解码器用于将字符序列转换为已编码的字节序列
   e.GetBytes(charData, 0, charData.Length, byteData, 0, true);
//将字符数组charData的0(当前)位置开始把所有字符转换到byteData字节数组中,true便是转换后清除编码器内部状态
//文件指针指向文件开始位置
     aFile.Seek(0, SeekOrigin.Begin);
      //开始写入文件
      aFile.Write(byteData, 0, byteData.Length);
 }
}
 catch (IOException ex)
{
    Console.WriteLine("文件操作异常");
    Console.WriteLine(ex.ToString());
    Console.ReadKey();
    return;
}
Console.ReadKey();

由于FileStream类提供的方法操作的是字节数据,在读取文件时,读取到的是字节型数据,因此需要通过Decoder类把字节数据解码为字符数组,从而显示输出
在写入文件时,由于用户输入的字符数组数据(由字符串转换而得),则必须要转换为字节数组(通过Encoder类)才能通过FileStream类写入到文件。
读取
在这里插入图片描述

写入
在这里插入图片描述

Path类

在程序中经常会对文件的路径进行操作,C#中提供了Path类,Path类中包含了许多路径进行操作的方法。

  1. string Combine(params string[] paths)
    作用:将字符串或字符串数组组合成一个路径
  2. string GetDirectoryName(string path)
    作用:返回指定路径字符串的目录信息
  3. string GetExtension(string path)
    作用:返回指定的路径字符串的扩展名
  4. string GetFileName(string path)
    作用:返回指定路径字符串的文件名和扩展名
  5. string GetFullPath(string path)
    作用:返回指定路径字符串的绝对路径
  6. bool HasExtension(string path)
    作用:确定路径是否包括文件扩展名
  7. string GetPathRoot(string path)
    作用:获取指定路径的根目录信息
  8. string GetTempPath()
    作用:返回当前用户的临时文件夹的路径
  9. string GetTempFileName()
    作用:创建磁盘上唯一命名的零字节的临时文件并返回该文件的完整路径
  10. string ChangeExtension(string path,string extension)
    作用:更改路径字符串的扩展名,仅更改路径字符串中的扩展名,并不会改变实际文件的扩展名
string path = @"E:\temp\File\Data.txt";
//修改文件的扩展名
string str = Path.ChangeExtension(path, "exe");
Console.WriteLine("修改文件扩展名后:"+str);
//拼接路径E:\temp\和路径File\Data.txt
string path1 = Path.Combine(@"E:\temp\", @"File\Data.txt");
//如果第二个参数(后边字符)第一个字符为\的话,则会取相对路径输出(只输出第二个字符串参数),也即不能完成拼接
Console.WriteLine("拼接后的路径:"+path1);
//获取文件或文件夹的路径
string path2 = Path.GetDirectoryName(path);
Console.WriteLine("返回的目录信息为:"+path2);
//获取扩展名:包含点,如果要做类型的进一步判断,需要去掉点
string ext = Path.GetExtension(path);
Console.WriteLine("获取扩展名为:"+ext);
//获取文件名:包含扩展名,不包含扩展名
Console.WriteLine("包含扩展名:"+Path.GetFileName(path));
Console.WriteLine("不包含扩展名:"+Path.GetFileNameWithoutExtension(path));
//由相对路径获取绝对路径
string str1 = Path.GetFullPath("Data.txt");
Console.WriteLine("全路径名字:"+str1);
Console.ReadLine();

序号化和反序列化

在程序开发中有时需要传输和保存对象,但对象是无法直接进行数据传输和保存的,所有C#中提供了序列化和反序列化
1、什么是序列化
序列化是指将对象状态转换为可传输或保存的过程,此时必须使用Serializable标签标记该对象。也可以这样理解:将对象转为二进制存储到一个文件。
2、什么是反序列化
反序列化是指将存储的流转换为对象的过程

            //构造一个用于序列化操作的对象
            Person p = new Person();
            p.Name = "fengyu";
            p.Age = 5;
            //构造序列化器对象
            BinaryFormatter bf = new BinaryFormatter();
            //构造输出流
            using (FileStream fs = new FileStream("Data.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {//第2个参数表示文件存在就打开,不存在就创建,第3个参数表示可以从文件读取数据和将数据写入文件(Read、Write、ReadWrite三种)
                //进行序列化输出操作(调用序列化器对象的Serialize方法将p对象经由文件流fs方式写入到Data.txt文件)
                bf.Serialize(fs, p);
                Console.WriteLine("序列化操作成功,对象已写入文件");
            }
            using (FileStream fs1 = new FileStream("Data.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                //反序列化是指将存储的流转转换为对象的过程
                //进行反序列化,返回一个object类型的对象
                object obj = bf.Deserialize(fs1);
                Console.WriteLine("反序列化对象数据为:"+obj.ToString());
            }
            Console.ReadKey();


 [Serializable]
        //Serializable标签标记Person类,让Person类型的对象p可以被传输或存储
        public class Person
        {
            public int Age
            {
                get;
                set;
            }
            public string Name
            {
                get;
                set;
            }
            public override string ToString()
            {
                return string.Format("Name:{0},Age:{1}", this.Name, this.Age);
            }
        }

BufferedStream类

BufferedStream类用于将文件临时存储到缓冲区中,方便以后读取。BufferedStream类必须和其他流一起使用,并将这些流写入内存中,这样可以提高读取和写入速度。
BufferedStream提供了几个常用的操作方法,Read()方法、Write()方法和Flush()方法。

  1. Read()方法
    Read()方法用于读取缓冲区中的数据
public override int Read(byte[] array ,int offset ,int count)

Read()方法有三个参数。
第一个参数array表示将字节复制到缓冲区。
第二个参数offset表示索引位置,从此处开始读取字节。
第三个参数count表示要读取的字节数。
该方法的返回值是一个int类型,表示读取array字节数组中的总字节数,如果实际字节小于请求的字节数,就返回时间读取的字节数。

  1. Write()方法
    Write()方法用于将字节复制到缓冲区,并在缓冲流内的当前位置继续写入字节
public override int Write(byte[] array,int offset,int count);

该方法同样有三个参数,其作用于Read()方法中参数的作用类似,只不过都是针对字节进行写入操作。

  1. Flush()方法
    Flush()方法用于清除当前流中的所有缓冲区,使得所有缓冲的数据都被写入到存储设备中。
public override void Flush()
            int i;
            FileStream myStream1, myStream2;
            BufferedStream myBStream1, myBStream2;
            byte[] myByte = new byte[1024];//定义字节数组
            //复制前
            Console.WriteLine("读取前");
            Print("Data2.txt");
            myStream1 = File.OpenRead("Data1.txt");//创建读取文件流
            myStream2 = File.OpenWrite("Data2.txt");//创建写入文件流
            myBStream1 = new BufferedStream(myStream1);//实例化缓冲流对象
            myBStream2 = new BufferedStream(myStream2);//实例化缓冲流对象
            i = myBStream1.Read(myByte, 0, 1024);//从读取流中读取数据到字节数组(换从区中),返回读取的字节数
            while (i > 0)
            {
                myBStream2.Write(myByte, 0, i);
                //把缓冲区(字节数组)中的数据写入到缓冲写入流中。即向myBStream2流对象中写入内容
                i = myBStream1.Read(myByte, 0, 1024);
            }

            myBStream2.Flush();
            //清空当前流的缓冲空间,使得所有缓冲的数据都被写入到存储设备中,
            //如果没有此句话,那么缓冲区装满了才会写入设备(文件)中
            //即是没有达到1024字节数据就不会写入到文件中
            myBStream1.Close();
            myBStream2.Close();//关闭当前流对象
            //复制之后
            Console.WriteLine("读取后");
            Print("Data2.txt");
            Console.ReadKey();

            #endregion

        }
        public static void Print(string path)
        {
            using (StreamReader sr = new StreamReader(path, Encoding.Default))
            {
                string content = sr.ReadToEnd();
                Console.WriteLine("文件{0}内容为:{1}",path,content);
            }
        }

分析:首先将读取的数据存入定义好的字节数组,然后将字节数组的数据一次性写入文件中
在这里插入图片描述说明:
由于缓冲流在内存的缓冲区中直接读取数据,而不是从磁盘中直接读取数据,所有处理效率较高,处理大容量的文件比较合适。

StreamReader类

  StreamReader类以字符的形式读取文件,在创建StreamReader时可以通过FileStream对象来创建,同时也可以直接创建StreamReader对象。
  当FileStream类的对象存在时可以通过该对象来创建StreamReader对象

FileStream aFile=new FileStream("Data.txt",FileMode.Open);
StreamReader sr=new StreamReader(aFile);

StreamReader与StreamWriter一样,可以通过具体文件路径的字符串来创建StreamReader对象

StreamReader sr=new StreamReader("Data.txt");
 string line;
 string path = @"E:\temp\data.txt";
 try
 {
   //打开路径为path的文件
   FileStream aFile = new FileStream(path, FileMode.Open);//使用FileStream对象打开文件
   StreamReader sr = new StreamReader(aFile, Encoding.Default);//创建读取流对象,第二个参数读取采用的编码方式,设置Encoder.Default防止读取的中文出现乱码
   line = sr.ReadLine();//读取文件中的第一行
   while (line != null)//如果文件不为空继续读取文件并输出至控制台
      {
            Console.WriteLine(line);
            line = sr.ReadLine();
      }
            sr.Close();//当文件读取完毕后,关闭当前流对象
  }
  catch (IOException ex)
  {
        Console.WriteLine("文件操作异常");
        Console.WriteLine(ex.ToString());//输入异常原因
  }
  Console.ReadKey();

1、可以直接使用StreamReader类通过给定路径创建读取流对象

StreamReader sr=new StreamReader(path,Encoding.Default);

2、可以直接通过sr.ReadLine()一行行读取数据,一次性读取到末尾

Console.WriteLine(sr.ReadToEnd());

用StreamWriter、StreamReader进行文件读写

   string temp;
            StreamWriter sw = new StreamWriter("Data.txt", true, Encoding.Default);
            sw.WriteLine("欢迎来到fengyu!");
            sw.Close();//关闭StreamWriter文件流
            StreamReader sr = new StreamReader("Data.txt", Encoding.Default);

            //逐步读取数据,如果未读取到数据则返回null
            while ((temp = sr.ReadLine()) != null)
            {
                Console.WriteLine(temp);
               
            }
            //Console.WriteLine(sr.ReadToEnd());可以替换上述代码
            sr.Close();//关闭StreamReader文件流
            sr.Dispose();//释放StreamReader对象
            sw.Dispose();//释放StreamWriter对象
            Console.ReadKey();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1394105.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kotlin学习最快速的方式

引言: 前段时间在一个技术交流群看到一句话:"在我面试的过程中,遇到一位面试者,做ios开发的,Swift 语言出来4-5年了,30多岁的人,连这个都不会";今天再次回想了这句话,说的不正我这样的人吗?一个之前做Anroid应用开发的,现在连Kotlin都不会;做技术的,还是要紧跟时代…

基于YOLOv8深度学习的智能肺炎诊断系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

数组中第K个最大元素(算法村第十关白银挑战)

215. 数组中的第K个最大元素 - 力扣(LeetCode) 给定整数数组 nums 和整数 k,请返回数组中第 **k** 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现…

Leetcode刷题-(1~5)-Java+Python+JavaScript

算法题是程序员的基本功,也是各个大厂必考察的重点,让我们一起坚持写算法题吧 遇事不决,可问春风,春风不语,即是本心。 我们在我们能力范围内,做好我们该做的事,然后相信一切都事最好的安排就…

【AI接口】语音版、文心一言大模型和AI绘图、图片检测API

文章目录 一、语音版大模型AI1、接口2、请求参数3、请求参数示例4、接口返回示例 二、AI图片鉴黄合规检测API1、接口2、请求参数3、请求参数示例4、接口返回示例5、报错说明6、代码开源 三、人工智能AI绘画API1、接口2、请求参数3、请求参数示例4、接口返回示例5、AI绘画成果展…

rabbitmq-java基础详解

一、rabbitmq是什么? 1、MQ定义 MQ(Message Queue)消息队列 主要解决:异步处理、应用解耦、流量削峰等问题,是分布式系统的重要组件,从而实现高性能,高可用,可伸缩和最终一致性的架…

LabVIEW精确测量产品中按键力和行程

项目背景 传统的按键测试方法涉及手工操作,导致不一致和效率低下。在汽车行业中,带有实体按键的控制面板非常常见,确保一致的按键质量至关重要。制造商经常在这些组件的大规模、准确测试中遇到困难。显然,需要一个更自动化、精确…

Unity3D和three.js的比较

一、Unity3D和three.js简介 Unity3D是一款跨平台的游戏引擎,可以用于开发2D和3D游戏。它提供了一个可视化的开发环境,包含了强大的编辑器和工具,使开发者可以方便地创建游戏场景、添加物体、设置物理效果、编写脚本等。Unity3D支持多种平台,包括PC、移动设备、主机等,可以…

uniapp uni.chooseLocation调用走失败那里,错误码:112

问题:我配置了百度上所有能配置的,一直调用不成功,如下图配置的 1:第一个 配置 代码: "permission": {"scope.userLocation": {"desc": "你的位置信息将用于小程序位置接口的效果展示"}…

华为设备NAT的配置

实现内网外网地址转换 静态转换 AR1: sys int g0/0/0 ip add 192.168.10.254 24 int g0/0/1 ip add 22.33.44.55 24 //静态转换 nat static global 22.33.44.56 inside 192.168.10.1 动态转换 最多有两台主机同时访问外网 AR1: sys int g0/0/0 ip add…

【前沿技术杂谈:人工智能与种族主义 】谷歌在其视觉人工智能产生种族主义结果后道歉

【前沿技术杂谈:人工智能与种族主义 】谷歌在其视觉人工智能产生种族主义结果后道歉 背景调查现实世界的后果渐进式改变 一项自动标记图像的谷歌服务会根据给定图像的肤色产生截然不同的结果。该公司解决了这个问题,但问题可能更广泛。 为抗击新冠病毒&…

KubeSphere 开源社区 2023 年度回顾与致谢

2023 年结束了,让我们再一次一起回顾一下 KubeSphere 开源社区在过去一年的变化。更重要的是,本篇文章将会对 2023 年所有参与过 KubeSphere 社区贡献的成员致以最诚挚的感谢,快来看看有没有你! 开源项目发展情况 2023 年&#…

C语言:数据在内存中的存储形式

一、整数在内存中的存储 关于整数在内存中的存储形式,在博主之前写的文章里已经介绍了!友友们可以去点下面链接去看,这里就不过多介绍。 C语言:进制的转换以及原码、反码、补码 我们以整型在内存中的存储形式为基础&#xff0c…

k8s---ingress对外服务(ingress-controller)

ingress 概念 k8s的对外服务,ingress service作用现在两个方面: 1、集群内部:不断跟踪的变化,更新endpoint中的pod对象,基于pod的ip地址不断变化的一种服务发现机制。 2、集群外部:类似于负载均衡器&a…

群晖nas内网穿透

目录 一、前言 二、操作步骤 (一)查看群晖是否有ipv6地址 (二)下载安装docker (三)docker里面安装ddns-go (四)阿里云官网购买域名 (五)域名解析 阿里…

如何实现无公网ip远程访问内网本地BUG管理服务【内网穿透】

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

python数字图像处理基础(五)——Canny边缘检测、图像金字塔、图像分割

目录 Canny边缘检测原理步骤 图像金字塔1.高斯金字塔2.拉普拉斯金字塔 图像分割图像轮廓检测1.检测轮廓2.绘制轮廓3.补充 Canny边缘检测 梯度是什么? 梯度就是变化的最快的那个方向 edge cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]…

MySql三方工具

Yearning 1.1.1 Yearning简介 Yearning 开源的MySQL SQL语句审核平台,提供数据库字典查询,查询审计,SQL审核等多种功能。 Yearning 1.x 版本需Inception提供SQL审核及回滚功能。 Inception是集审核,执行,回滚于一体的…

RK3568 android11 移植 v4l2loopback 虚拟摄像头

一,v4l2loopback 简介 v4l2loopback是一个Linux内核模块,它允许用户创建虚拟视频设备。这种虚拟视频设备可以用于各种用途,例如将实际摄像头的视频流复制到虚拟设备上,或者用于视频流的处理和分析等。v4l2loopback的主要作用是创…

《WebKit 技术内幕》之三(3): WebKit 架构和模块

3 Webkit2 3.1 Webkit2 架构及模块 相比于狭义的WebKit,WebKit2是一套全新的结构和接口,而并不是一个简单的升级版。Webkit2 的思想同 Chrominum 类似,就是将渲染过程放在单独的进程中来完成,独立于用户界面。 webKit2中…