GDAL的最大波段数限制及最大文件数限制

Posted 深蓝静音

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GDAL的最大波段数限制及最大文件数限制相关的知识,希望对你有一定的参考价值。

GDAL的最大波段数限制及最大文件数限制

最大波段数限制

GDAL写文件时,一个文件最多可以有多少个波段呢?

	int nMaxBandCount = atoi(CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65535"));
	printf("Max band count:%d\\n", nMaxBandCount);

我们可以用CPLSetConfigOption来修改这个数值:

	//设置最大波段数
	CPLSetConfigOption("GDAL_MAX_BAND_COUNT", "65536");

那么这个数值最大能多大呢?

根据源码中的逻辑,在gcore\\gdal_misc.cpp中,GDALCheckBandCount中进行波段数目检查:

int GDALCheckBandCount( int nBands, int bIsZeroAllowed )
{
   if (nBands < 0 || (!bIsZeroAllowed && nBands == 0) )
   {
       CPLError(CE_Failure, CPLE_AppDefined,
                "Invalid band count : %d", nBands);
       return FALSE;
   }
   const char* pszMaxBandCount = CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536");
   /* coverity[tainted_data] */
   int nMaxBands = atoi(pszMaxBandCount);
   if ( nBands > nMaxBands )
   {
       CPLError(CE_Failure, CPLE_AppDefined,
                "Invalid band count : %d. Maximum allowed currently is %d. "
                "Define GDAL_MAX_BAND_COUNT to a higher level if it is a legitimate number.",
                nBands, nMaxBands);
       return FALSE;
   }
   return TRUE;
}

其中CPLGetConfigOption的定义如下:

const char * CPL_STDCALL
CPLGetConfigOption( const char *pszKey, const char *pszDefault )

{
#ifdef DEBUG_CONFIG_OPTIONS
    CPLAccessConfigOption(pszKey, TRUE);
#endif

    const char *pszResult = NULL;

    int bMemoryError = FALSE;
    char **papszTLConfigOptions = reinterpret_cast<char **>(
        CPLGetTLSEx(CTLS_CONFIGOPTIONS, &bMemoryError));
    if( papszTLConfigOptions != NULL )
        pszResult = CSLFetchNameValue(papszTLConfigOptions, pszKey);

    if( pszResult == NULL )
    {
        CPLMutexHolderD(&hConfigMutex);

        pszResult =
            CSLFetchNameValue(const_cast<char **>(g_papszConfigOptions), pszKey);
    }

    if( pszResult == NULL )
        pszResult = getenv(pszKey);

    if( pszResult == NULL )
        return pszDefault;

    return pszResult;
}

可以看到,源码中的逻辑是先从默认设置开始取值,如果没有,从环境变量中取值,否则返回默认值,并且这个值在源码中是一个int型的整数,所以其最大值就是int的最大值2147483647。
根据以上信息可知,除了用CPLSetConfigOption设置最大波段数外,还可以通过环境变量来设置,并且环境变量的优先级最高:
Linux下:
export GDAL_MAX_BAND_COUNT=2147483647

最大文件数量限制

在unix系统下,使用GDALOpen打开ENVI文件,会遇到打开文件数量511个后继续打开就会失败的问题。追查源码就会发现,这个问题的如下:

  gcore\\gdaldataset.cpp    		GDALOpenEx  -->
  frmts\\raw\\envidataset.cpp		ENVIDataset::Open --> 
  port\\cpl_vsil.cpp			VSIFOpenExL -->
  port\\cpl_vsil_unix_stdio_64.cpp 	VSIUnixStdioFilesystemHandler::Open -->
  iofopen.c			fopen64

最后会发现,是系统的fopen64返回了NULL。系统底层的io函数为啥会返回null呢?
这是因为unix系统对于打开文件的句柄数量有限制,通过ulimit -a就可以看到最大文件数量限制,一般默认1024个,这就是为啥我们打开ENVI格式的文件,到511个就失败了。
ENVI的文件,会打开一个数据文件,同时打开一个头文件,一个文件占用两个fp,所以打开第512个时,读到头文件就1024个了,所以就打开失败了。
针对此问题,可以通过修改unix系统的最大文件数量来解决,不过最好的办法就是不要用GDALOpen缓存这么多的GDALDataset。

ubuntu临时修改文件数量的方法是:

  ulimit -SHn 1048576

ulimit 命令身分软限制和硬限制,硬限制就是实际的限制,而软限制是警告限制,它只会给出警告。
加-H就是硬限制,加-S就是软限制。默认显示的是软限制,如果运行ulimit 命令修改时没有加上-H或-S,就是两个参数一起改变。

永久生效的方法是修改文件: sudo vi /etc/security/limits.conf
添加

* soft nofile 65535   
* hard nofile 65535  

sudo echo "* soft nofile 65535"  >> /etc/security/limits.conf
sudo echo "* hard nofile 65535"  >> /etc/security/limits.conf

上面是一个进程打开文件数量的限制,除此以外,可能还存在系统总的限制,我看查看该限制:

cat /proc/sys/fs/file-max

可以临时修改这个限制:

sudo echo 26336040 > /proc/sys/fs/file-max

临时修改在机器重启后就会失效,要想永久生效,修改配置:

sudo vi /etc/sysctl.conf

加入

fs.file-max = 26336040

以上是关于GDAL的最大波段数限制及最大文件数限制的主要内容,如果未能解决你的问题,请参考以下文章

GDAL的最大波段数限制及最大文件数限制

GDAL的最大波段数限制及最大文件数限制

Linux中最大进程数和最大文件数

Linux 下最大文件数等限制

Linux最大打开文件数

Linux下TCP最大连接数受限问题