GDAL VSI文件扩展(virtual_file_systems扩展)
需求: 需要支持 远程打开 FTP或者网络上的 tif或者img文件, 但是GDAL不能依赖curl编译, 无法直接使用 /vsicurl/ftp://192.168.0.22/a.tif 这种路径丢给GDALOpen去打开tif文件;
解决方案:
GDAL在支持ftp或者网络数据集得时候定义了一套虚拟文件系统接口, 所有打开本地或者远程资源都是用 VSIFilesystemHandler 和 VSIVirtualHandle.这两个接口操作.
经过研究发现只需要实现以上两个接口并注册进GDAL里面他就会自动来根据操作打开文件,然后去读取文件内容.
需要自行实现一个 VSIFilesystemHandler 和 VSIVirtualHandle.
其中VSIFilesystemHandler需要实现以下接口
//需要实现以下接口
class CPL_DLL VSIFilesystemHandler {virtual VSIVirtualHandle *Open( const char *pszFilename,const char *pszAccess,bool bSetError,CSLConstList papszOptions ) = 0;virtual int Stat( const char *pszFilename, VSIStatBufL *pStatBuf, int nFlags) = 0;
}
VSIVirtualHandle需要是实现以下接口
class CPL_DLL VSIVirtualHandle {public:virtual int Seek( vsi_l_offset nOffset, int nWhence ) = 0;virtual vsi_l_offset Tell() = 0;virtual size_t Read( void *pBuffer, size_t nSize, size_t nCount ) = 0;virtual size_t Write( const void *pBuffer, size_t nSize,size_t nCount)=0;virtual int Eof() = 0;virtual int Close() = 0;
}
最后在打开数据之前还需要注册一下:
VSIFileManager::InstallHandler(file.FullPath().c_str(), new cpl::GsVSIFilesystemHandler(file.FullPath().c_str(), pGDB));
m_pDS = (GDALDataset *)GDALOpen(file.FullPath().c_str(), GA_ReadOnly);
本文实现远程ftp文件访问并用GDAL解析, 具体代码如下:
#include "pch.h"
#include "vsifileimp.h"using namespace GeoStar::Kernel;
using namespace GeoStar::Utility;//FTP 实现的坑, FTP同一文件一个流没读完,下一个流不起作用, (IMG文件gdal内部需要打开和关闭两次)
//FTP 文件流不支持seek ,只能下载向前读, 这在tif文件得时候是可以得, 但是在img不行,
//FTP 不要视图多线程, 因为只能打开一个文件流,
//FTP 镶嵌数据集支持ftp是个玩具,需要上对象化存储int cpl::GsVSIVirtualHandle::Eof()
{return beof;
}
//return 0 on success or -1 one failure.
int cpl::GsVSIVirtualHandle::Seek(vsi_l_offset nOffset, int nWhence)
{if (nOffset < 0 || nOffset > filesize)return -1;if (nWhence == SEEK_SET){curOffset = nOffset;}else if (nWhence == SEEK_CUR){curOffset = curOffset + nOffset;}else{curOffset = filesize + nOffset;}beof = false;return 0;
}
//*@return 0 on success or -1 on failure.
vsi_l_offset cpl::GsVSIVirtualHandle::Tell()
{return curOffset;
}
//
//size_t cpl::GsVSIVirtualHandle::Read(void * pBufferIn, size_t nSize, size_t nCount)
//{
// if (0 == nSize * nCount)
// return 0;
// unsigned char*pbufferhead = (unsigned char*)pBufferIn;
// unsigned long long needsize = nCount * nSize;
//
// if (needsize + curOffset <= loadsize)
// {
// GsInputStreamPtr read = m_TmpFile->OpenRead();
// read->Seek(curOffset, GsStreamSeekOrigin::eSet);
// int n = read->RawRead((unsigned char*)pbufferhead, needsize);
// curOffset += n;
// return n;
// }
// unsigned long long AllReturnSize = 0;
// long long Infilesize = loadsize - curOffset;
// if (Infilesize > 0)
// {
// GsInputStreamPtr read = m_TmpFile->OpenRead();
// int tmpfileread = read->RawRead((unsigned char*)pbufferhead, needsize);
// pbufferhead += tmpfileread;
// needsize -= tmpfileread;
// curOffset += tmpfileread;
// AllReturnSize += tmpfileread;
// }
// unsigned long long outfilesize = fabs(Infilesize);
// unsigned long long needdownsize = outfilesize + needsize;
// int buffsize = 1024;
// GsGrowByteBuffer buff;
// buff.Allocate(buffsize);
// {auto write = m_TmpFile->OpenWrite();
// unsigned long long downCount = 0;
// //直接放文件
// if (outfilesize < buffsize)
// buffsize = outfilesize;
// while (outfilesize > 0)
// {
// int n = this->FTPRead(buff.BufferHead(), 1, buffsize);
// if (n <= 0)
// break;
// downCount += n;
// outfilesize -= n;
// if (outfilesize < buffsize)
// buffsize = outfilesize;
// loadsize += n;
// buff.Allocate(n);
// write->WriteBuffer(&buff);
// }
//
// buffsize = 1024;
// int tmpwritecount = 0;
// if (needsize < buffsize)
// buffsize = needsize;
// while (needsize > 0)
// {
// int n = this->FTPRead(pbufferhead, 1, buffsize);
// if (n <= 0)
// break;
//
// buff.Allocate(n);
// buff.Copy(pbufferhead, n);
// tmpwritecount += write->WriteBuffer(&buff);
// pbufferhead += n;
// needsize -= n;
// AllReturnSize += n;
// curOffset += n;
// loadsize += n;
// if (needsize < buffsize)
// buffsize = needsize;
// }
// write->Flush();
// write->Close();
// }
// //curOffset += AllReturnSize;
// return AllReturnSize;
//
//}
//#define BLOCKSIZE 1024*16
//size_t cpl::GsVSIVirtualHandle::Read(void * pBufferIn, size_t nSize, size_t nCount)
//{
// if (0 == nSize * nCount)
// return 0;
// unsigned char*pbufferhead = (unsigned char*)pBufferIn;
// long long needsize = nCount * nSize;
//
// if (needsize + curOffset <= loadsize)
// {
// FILE* file = fopen(m_tmpFilePath.c_str(), "r");
// fseek(file, curOffset, 0);
// int n = fread((unsigned char*)pbufferhead, nSize, nCount, file);
// curOffset += n;
// fclose(file);
// return n;
// }
// long long AllReturnSize = 0;
// long long Infilesize = loadsize - curOffset;
// if (Infilesize > 0)
// {
// FILE* file = fopen(m_tmpFilePath.c_str(), "r");
// fseek(file, curOffset, 0);
// int tmpfileread = fread((unsigned char*)pbufferhead, 1, needsize, file);
// fclose(file);
// pbufferhead += tmpfileread;
// needsize -= tmpfileread;
// curOffset += tmpfileread;
// AllReturnSize += tmpfileread;
// }
// long long outfilesize = fabs(Infilesize);
// long long needdownsize = outfilesize + needsize;
// int buffsize = BLOCKSIZE;
// GsGrowByteBuffer buff;
// int tmp = 0;
// buff.Allocate(buffsize);
// {
// FILE* file = fopen(m_tmpFilePath.c_str(), "a+");
// long long downCount = 0;
// //直接放文件
// //if (outfilesize < buffsize)
// //buffsize = outfilesize;
// while (outfilesize > 0)
// {
// int n = this->FTPRead(buff.BufferHead(), 1, buffsize);
// if (n <= 0)
// break;
//
// if (outfilesize < n)
// {
// buff.Allocate(outfilesize);
// }
// else
// {
// buff.Allocate(n);
// }
// tmp = fwrite(buff.BufferHead(), 1, buff.BufferSize(), file);
// downCount += n;
// outfilesize -= n;
// loadsize += n;
//
// }
//
// buffsize = BLOCKSIZE;
// int tmpwritecount = 0;
// buff.Allocate(buffsize);
// //if (needsize < buffsize)
// // buffsize = needsize;
// while (needsize > 0)
// {
// int n = this->FTPRead(buff.BufferHead(), 1, buffsize);
// if (n <= 0)
// break;
//
// buff.Allocate(n);
// tmpwritecount += fwrite(buff.BufferHead(), 1, buff.BufferSize(), file);
//
// if (needsize < n)
// {
// buffsize = needsize;
// memcpy(pbufferhead, buff.BufferHead(), needsize);
// //pbufferhead += n;
// //needsize -= n;
// AllReturnSize += needsize;
// curOffset += needsize;
// loadsize += n;
// }
// else
// {
// memcpy(pbufferhead, buff.BufferHead(), n);
// pbufferhead += n;
// needsize -= n;
// AllReturnSize += n;
// curOffset += n;
// loadsize += n;
// }
//
//
// }
// fflush(file);
// fclose(file);
// }
//
// return AllReturnSize;
//
//}#define BLOCKSIZE 1024
#define BLOCKSIZE_C 1024
#define BLOCKSIZE_RC BLOCKSIZE*BLOCKSIZE * BLOCKSIZE_C
//分段读取目前是不成功, 在img文件的ftp文件中, 这里不停得打开关闭文件存在问题
size_t cpl::GsVSIVirtualHandle::Read2(void * pBufferIn, size_t nSize, size_t nCount)
{if (0 == nSize * nCount)return 0;unsigned char*pbufferhead = (unsigned char*)pBufferIn;unsigned long long needsize = nCount * nSize;if (needsize + curOffset > filesize)return 0;if (needsize + curOffset <= loadsize){FILE* file = fopen(m_tmpFilePath.c_str(), "rb");fseek(file, curOffset, 0);int n = fread((unsigned char*)pbufferhead, nSize, nCount, file);curOffset += n;fclose(file);return n;}unsigned long long AllReturnSize = 0;long long Infilesize = (loadsize > curOffset) ? (loadsize - curOffset) : (-1 * (curOffset - loadsize));if (Infilesize > 0){FILE* file = fopen(m_tmpFilePath.c_str(), "rb");fseek(file, curOffset, 0);int tmpfileread = fread((unsigned char*)pbufferhead, 1, needsize, file);fclose(file);pbufferhead += tmpfileread;needsize -= tmpfileread;curOffset += tmpfileread;AllReturnSize += tmpfileread;}unsigned long long outfilesize = fabs(Infilesize);unsigned long long needdownsize = outfilesize + needsize;int buffsize = BLOCKSIZE;GsGrowByteBuffer buff;int tmp = 0;buff.Allocate(buffsize);{FILE* file = fopen(m_tmpFilePath.c_str(), "ab+");unsigned long long downCount = 0;//直接放文件if (outfilesize < buffsize)buffsize = outfilesize;while (outfilesize > 0){int n = this->FTPRead(buff.BufferHead(), 1, buffsize);if (n <= 0)break;downCount += n;outfilesize -= n;loadsize += n;if (outfilesize < n)buffsize = outfilesize;buff.Allocate(n);tmp = fwrite(buff.BufferHead(), 1, buff.BufferSize(), file);}buffsize = BLOCKSIZE;int tmpwritecount = 0;buff.Allocate(buffsize);if (needsize < buffsize)buffsize = needsize;while (needsize > 0){int n = this->FTPRead(pbufferhead, 1, buffsize);if (n <= 0)break;needsize -= n;AllReturnSize += n;curOffset += n;loadsize += n;buff.Allocate(n);buff.Copy(pbufferhead, n);tmpwritecount += fwrite(buff.BufferHead(), 1, buff.BufferSize(), file);if (needsize < n)buffsize = needsize;pbufferhead += n;}fflush(file);fclose(file);}return AllReturnSize < 0 ? -1 : AllReturnSize;
}
size_t cpl::GsVSIVirtualHandle::ReadLocal(void * pBufferIn, size_t nSize, size_t nCount)
{if (0 == nSize * nCount)return 0;unsigned char*pbufferhead = (unsigned char*)pBufferIn;unsigned long long needsize = nCount * nSize;if (needsize + curOffset <= loadsize){//if (!rfile)FILE* rfile = fopen(m_tmpFilePath.c_str(), "rb");int f = fseek(rfile, curOffset, 0);int n = fread((unsigned char*)pbufferhead, nSize, nCount, rfile);curOffset += n * nSize;//防止句柄耗尽,及时关闭fclose(rfile);return n;}return 0;
}
size_t cpl::GsVSIVirtualHandle::Read2Local(void * pBuffer, size_t nSize, size_t nCount)
{unsigned long long needsize = nCount * nSize;{GsGrowByteBuffer buff;long long tmpwritecount = 0;buff.Allocate(BLOCKSIZE);//if (!wfile)FILE* wfile = fopen(m_tmpFilePath.c_str(), "ab+");long long needDownsize = (long long)curOffset - (long long)loadsize + (long long)needsize;if (filesize < BLOCKSIZE_RC)needDownsize = filesize;else if (filesize > BLOCKSIZE_RC){if (needDownsize < BLOCKSIZE_RC)needDownsize = BLOCKSIZE_RC;//if (needDownsize + loadsize > filesize)//{// needDownsize = (long long) filesize - (long long)loadsize;//}}while (needDownsize > 0){buff.Allocate(BLOCKSIZE);int n = this->FTPRead(buff.BufferHead(), 1, BLOCKSIZE);if (n <= 0)break;loadsize += n;buff.Allocate(n);needDownsize -= n;tmpwritecount += fwrite(buff.BufferHead(), 1, buff.BufferSize(), wfile);}fflush(wfile);防止句柄耗尽,及时关闭fclose(wfile);return tmpwritecount;}
}
size_t cpl::GsVSIVirtualHandle::Read(void * pBufferIn, size_t nSize, size_t nCount)
{unsigned long long needsize = nCount * nSize;if (filesize >0 && needsize + curOffset > filesize)return 0;int n = ReadLocal(pBufferIn, nSize, nCount);if (n > 0)return n;size_t writecount = Read2Local(pBufferIn, nSize, nCount);return ReadLocal(pBufferIn, nSize, nCount);
}
cpl::GsVSIVirtualHandle::GsVSIVirtualHandle(GeoStar::Utility::GsVirtualFile * file)
{m_File = file;GsString tmpFile = GsFileSystem::TemporaryFolder();m_tmpFilePath = GsFileSystem::Combine(tmpFile.c_str(), GsMath::NewGUID().c_str());filesize = m_File->Size();
}cpl::GsVSIVirtualHandle::~GsVSIVirtualHandle()
{if (m_File){GsFile::Delete(m_tmpFilePath.c_str());m_File = NULL;}}size_t cpl::GsVSIVirtualHandle::FTPRead(void * pBufferIn, size_t nSize, size_t nCount)
{if (!m_ReadHandle)m_ReadHandle = m_File->OpenRead();if (!m_ReadHandle)return 0;long long nRawCount = nSize * nCount;if (0 == nRawCount)return 0;int r = m_ReadHandle->RawRead((unsigned char*)pBufferIn, nRawCount);//int retrycount = 3;//for (int i = 0; i < retrycount; i++)//{// if (r != 0)// return r;// m_ReadHandle = m_File->OpenRead();// if (!m_ReadHandle)// return 0;// long long nRawCount = nSize * nCount;// if (0 == nRawCount)// return 0;// r = m_ReadHandle->RawRead((unsigned char*)pBufferIn, nRawCount);//}return r;
}size_t cpl::GsVSIVirtualHandle::Write(const void * pBuffer, size_t nSize, size_t nCount)
{return 0;
}
//return 0 on success or -1 on failure.
int cpl::GsVSIVirtualHandle::Close()
{防止句柄耗尽,及时关闭//fclose(rfile);//fclose(wfile);return 0;
}int cpl::GsVSIVirtualHandle::ReadMultiRange(int nRanges, void ** ppData,const vsi_l_offset* panOffsets,const size_t* panSizes)
{int nRet = 0;const vsi_l_offset nCurOffset = Tell();for (int i = 0; i < nRanges; i++){if (Seek(panOffsets[i], SEEK_SET) < 0){nRet = -1;break;}const size_t nRead = Read(ppData[i], 1, panSizes[i]);if (panSizes[i] != nRead){nRet = -1;break;}}Seek(nCurOffset, SEEK_SET);return nRet;
}cpl::GsVSIFilesystemHandler::GsVSIFilesystemHandler()
{
}cpl::GsVSIFilesystemHandler::GsVSIFilesystemHandler(GsVirtualFolder * foler)
{m_Root = foler;
}
cpl::GsVSIFilesystemHandler::GsVSIFilesystemHandler(const KERNEL_NAME::GsConnectProperty & conn, const UTILITY_NAME::GsConfig & conf)
{Init(conn, conf);
}
cpl::GsVSIFilesystemHandler::GsVSIFilesystemHandler(const char * file, KERNEL_NAME::GsGeoDatabase * pGdb)
{Init(file, pGdb);
}
GsString OpenType(const GsConnectProperty& conn, const GsConfig &conf)
{auto strVec = GsStringHelp::Split(conn.Server, ":");if (strVec.size() <= 0)return "Local";if (0 == GsStringHelp::CompareNoCase("Local", strVec[0])){return "Local";}else if (0 == GsStringHelp::CompareNoCase("FTP", strVec[0])){return "FTP";}else if (0 == GsStringHelp::CompareNoCase("WebDAV", strVec[0])){return "WebDAV";}else if (0 == GsStringHelp::CompareNoCase("OwnCloud", strVec[0])){return"OwnCloud";}else if (0 == GsStringHelp::CompareNoCase("NFS", strVec[0])){return"NFS";}else{return "Local";}
}
KERNEL_NAME::GsFileSystemClassPtr GetFS(const GsConnectProperty& conn, GsConfig &conf)
{UTILITY_NAME::GsObjectInstancerPtr ptrInstancer = UTILITY_NAME::GsClassFactory::CreateInstanceT<UTILITY_NAME::GsObjectInstancer>("FileSystemDataSourceFactory");if (!ptrInstancer){GS_W << "can't instance FileDataRoomCatalog ,need load gsspecialdatasource library first";return 0;}if (ptrInstancer->Exists("Server"))ptrInstancer->PropertyRef<UTILITY_NAME::GsString>("Server") = conn.Server;if (ptrInstancer->Exists("Database"))ptrInstancer->PropertyRef<UTILITY_NAME::GsString>("Database") = conn.Database;if (ptrInstancer->Exists("Password"))ptrInstancer->PropertyRef<UTILITY_NAME::GsString>("Password") = conn.Password;if (ptrInstancer->Exists("Port"))ptrInstancer->PropertyRef<int>("Port") = conn.Port;if (ptrInstancer->Exists("User"))ptrInstancer->PropertyRef<UTILITY_NAME::GsString>("User") = conn.User;if (ptrInstancer->Exists("Version"))ptrInstancer->PropertyRef<int>("Version") = conn.Version;if (ptrInstancer->Exists("Config"))ptrInstancer->PropertyRef<UTILITY_NAME::GsConfig>("Config") = conf;conf.Child("OpenType").Value(OpenType(conn, conf).c_str());return ptrInstancer->CreateInstanceT<KERNEL_NAME::GsFileSystemClass>();
}bool cpl::GsVSIFilesystemHandler::Init(const char*file, GsGeoDatabase* pGdb)
{GsConnectProperty conn = pGdb->ConnectProperty();m_Conf = pGdb->Config();m_Conn = conn;m_Conn.Server = file;m_ptrFsc = GetFS(m_Conn, m_Conf);if (m_ptrFsc)m_Root = m_ptrFsc->RootFolder();return !m_Root || !m_ptrFsc;
}
bool cpl::GsVSIFilesystemHandler::Init(const GsConnectProperty & conn, const GsConfig & conf)
{m_Conf = conf;m_Conn = conn;m_ptrFsc = GetFS(m_Conn, m_Conf);if (m_ptrFsc)m_Root = m_ptrFsc->RootFolder();return !m_Root || !m_ptrFsc;
}
GsString NonStandardUrlIP(const char * pszFilename) {GsString tmpstr = pszFilename;tmpstr = GsStringHelp::Replace(tmpstr.c_str(), "\\\\", "//");tmpstr = GsStringHelp::Replace(tmpstr.c_str(), "\\", "/");if (tmpstr.find("//") != tmpstr.npos){tmpstr = GsStringHelp::Replace(tmpstr.c_str(), "//", "/");auto tmps = GsStringHelp::Split(tmpstr.c_str(), "/");if (tmps.size() >= 2){tmpstr = tmps[1];}}return tmpstr;
}GsString NonStandardUrlBody(const char * pszFilename)
{GsString tmpstr = pszFilename;tmpstr = GsStringHelp::Replace(tmpstr.c_str(), "\\\\", "//");tmpstr = GsStringHelp::Replace(tmpstr.c_str(), "\\", "/");try{if (tmpstr.find("//") == tmpstr.npos)return tmpstr;if (tmpstr.size() > 6) {GsString mpstr = tmpstr.substr(6, tmpstr.size());auto st = mpstr.find("/");if (st != mpstr.npos){tmpstr = mpstr.substr(st + 1, mpstr.size());}}}catch (const std::exception & ex){GS_W << ex.what();}return tmpstr;
}VSIVirtualHandle * cpl::GsVSIFilesystemHandler::Open(const char * pszFilename, const char * pszAccess, bool bSetError, CSLConstList papszOptions)
{if (!m_Root)return 0;GsString strtmp = NonStandardUrlBody(pszFilename);auto file = m_Root->SubFile(strtmp.c_str());if (!file)return 0;return new GsVSIVirtualHandle(file);
}int cpl::GsVSIFilesystemHandler::Stat(const char * pszFilename, VSIStatBufL * pStatBuf, int nFlags)
{if (!m_Root)return -1;GsVirtualFileSystemPtr ptrfg = m_Root;GsString strtmp = NonStandardUrlBody(pszFilename);GsVirtualFilePtr file = 0;file = m_Root->SubFile(strtmp.c_str());if (!file)return -1;GsAny nChunkSize = file->Attributes()->Attribute(GsVirtualFilesSystemAttributeType::eChunkSize);GsAny nFileID = file->Attributes()->Attribute(GsVirtualFilesSystemAttributeType::eFileID);GsAny nFileSize = file->Size(); //file->Attributes()->Attribute(GsVirtualFilesSystemAttributeType::eFileSize);pStatBuf->st_size = nFileSize.Empty() ? 0 : nFileSize.AsLongLong();//pStatBuf->st_dev = nFileSize.Empty() ? 0 : nFileSize.AsLongLong();return 0;
}//void VSIInstallCurlFileHandler(void)
//{
// VSIFilesystemHandler* poHandler = new cpl::VSICurlFilesystemHandler;
// VSIFileManager::InstallHandler("/vsicurl/", poHandler);
// VSIFileManager::InstallHandler("/vsicurl?", poHandler);
//}
//
//void VSIInstallCurlStreamingFileHandler(void)
//{
// VSIFileManager::InstallHandler("/vsicurl_streaming/",
// new VSICurlStreamingFSHandler);
//}
最后得效果就是可以跟访问本地文件一样访问远程得tif和img文件, 其他格式没有尝试.
但是这里有个限制我这里用得是FTP协议, 无法实现seek接口, 只能将文件一段段下载下来, 然后可以操作, 如果有那种远程资源访问能支持向前和向后seek文件就能完美了, 我也不用支持缓存了.
GDAL VSI文件扩展(virtual_file_systems扩展)相关推荐
- 修改数据库文件为自动扩展以达到表空间自动扩展的目的
转自:http://space.itpub.net/519536/viewspace-605541 表空间自动扩展 1.数据文件自动扩展的好处 1)不会出现因为没有剩余空间可以利用到数据无法写入 2) ...
- 开启php的文件上传扩展,linux中如何通过php.ini添加扩展?
在编译安装的时候,我只通过了以下命令来安装,然后我想像windows中那样修改 php.ini 就开启了扩展 ./configure \ --enable-fpm \ --with-fpm-user= ...
- Python Cookbook(第3版)中文版:15.18 传递已打开的文件给C扩展
15.18 传递已打开的文件给C扩展¶ 问题¶ 你在Python中有一个打开的文件对象,但是需要将它传给要使用这个文件的C扩展. 解决方案¶ 要将一个文件转换为一个整型的文件描述符,使用 PyFile ...
- crx文件里面的html文件,javascript – Chrome扩展程序:在crx文件中打开html,标签上没有图标...
您好我正在开发一个简单的chrome扩展,它通过在扩展名的.crx目录中打开index.html来替换当前的默认新标签页. 目前,新的标签页已经使用新的index.html页面进行了修改,但是标签上没 ...
- Windows系统批量修改文件后缀名/扩展名
查看文件 查看文件是否有扩展名,没有后缀名通过ctrl+E打开计算机,找到"工具"->"文件夹选项"->"查看",取消勾选& ...
- Linux的文件权限理解及文件种类与扩展名
前言 Linux的环境为一个多人多任务环境,因此出于各个用户之间的保密性原因,它的文件管理权限就显得十分重要. Linux一般将文件可读写身份分为三种类别,分别为: 拥有者(owner) 所属群组(g ...
- 计算机如何把文件设为隐藏,已知文件类型的扩展名如何设置显示与隐藏?
当你想把文件扩展名隐藏或是显示的时候,有木有突然感觉有那么一瞬间皱着眉头过呢?当你想要设置显示与隐藏扩展名的时候却莫名其妙的发现"隐藏已知文件类型的扩展名"这一项选不见了,心理莫名 ...
- windows服务器设置文件属性设置去掉隐藏已知文件类型的扩展名(即文件后缀名可见)
摘要: 1.文件后缀名不可见,系统运维过程容易发生同名不同后缀的文件操作混淆的情况 2.windows系统默认是文件后缀名不可见 3.所以需要更改一下配置. 4.操作步骤如下图: (1)点击组织-文件 ...
- 在VSCode中自定义文件类型和扩展名关联
目录 标题 概述 实现步骤 总结 标题 在 VSCode 中自定义文件类型和扩展名关联 Customize file type and extension associations in VSCode ...
最新文章
- Postgresql:删除及查询字段中包含单引号的数据
- JavaScript中 for、for in、for of、forEach等使用总结
- JDK8的排序大法!!
- nginx html解析插件,nginx配置信息的解析流程
- pandas 菜鸟_再见Numpy,Pandas!又一个数据分析神器横空出现!
- Zabbix Server安装部署
- HFSS阵列天线设计与仿真1
- DoIP协议一致性测试
- edittext 内容长度
- iEx.ec——云计算业务的区块链革命
- 周记——20151214
- linux qemu的使用教程,详解QEMU网络配置的方法
- HDLBits—Exams/ece241 2014 q7a
- CSDN日报20170217——《辞职信:写给我的“藤野先生”》
- Android弹出关闭输入法
- tEST 1 for NOIP 2017.9.9.
- SPI与I2C总线协议
- Android 10 Firewall blacklist 设置范例
- 基于已有模型,训练新数据的方法
- 浅谈JVM的双亲委派机制
热门文章
- Appium Python API 中文版文档
- python不同时间周期k线_Python量化交易基础讲堂-股票分笔数据跨周期处理
- ssh税务管理系统web源码
- 电大2020计算机基础,2020年电大形考计算机基础答案(22页)-原创力文档
- 智慧社区信息管理系统的设计与实现(论文打包下载)
- 多家上市公司纷纷加强布局人工智能/智库2861
- Adobe发布Flash/HTML5转换工具:袋鼠
- 80前的前辈,你们都做了些什么?!(四)
- docker安装gamit_科学网—Ubuntu18.04 安装gamit10.7安装 - 陈超的博文
- 远距离遥控智能驱鸟器