精华内容
下载资源
问答
  • 内存映射:外部存储单元,比如寄存器,作为内存的一部分出现在系统中,应该是常说的与内存统一编址,向以前调试过的ARM芯片S3C2410。(ARM是不是都这样?) 2.I/O映射:外设的存储单元和内存...

    一般说来,对外部设备的访问有两种不同的方式:

    1.内存映射:外部的存储单元,比如寄存器,作为内存的一部分出现在系统中,应该是常说的与内存统一编址,向以前调试过的ARM芯片S3C2410。(ARM是不是都这样?)

    2.I/O映射:外设的存储单元和内存分属两个不同的体系。访问内存的指令不能访问外设的存储单元。如X86中专门设立了IN/OUT指令。

    无论哪种映射方式,都需要一个办法将外设上的存储器映射到虚拟地址空间。-ioremap方法。

    • 对于内存页面,通常先在虚存空间分配一个虚拟区间,然后为此区间分配相应的物理内存页面并建立映射,而且这样的映射也不是一次就建立完毕,可以在访问这些虚存页面引起页面异常时逐步建立。

    • ioremap不同,先存在一个物理存储区间,需要从此物理地址出发找到一片虚存空间并建立起映射。另外,这样的需求只发生于对外部设备的操作,属于内核的事情,所以虚存空间位于系统空间。(3G以上)。这样的页面不服从动态的物理内存页面分配,也不服从kswapd的换出。
    展开全文
  • 文件存储前言文件存储内存内部存储外部存储内部存储操作API读写操作外部存储操作公共目录私有目录私有文件私有缓存 前言 众所周知,数据存储在每个应用中都会用到,那所用到的技术应该怎么选呢,这里Android给...

    前言

    众所周知,数据存储在每个应用中都会用到,那所用到的技术应该怎么选呢,这里Android给开发者提供了几种方法去保存常用应用数据,至于你想选择哪一种方式,取决于你的特定需求;例如这个数据是本应用私有的还是跟其它应用共享以及数据存储所需的内存空间等

    • Shared Preferences:这种方式通常用来保存私有原始数据,以键值对形式存储;这也就意味着这些数据只能由本应用访问
    • Internal Storage:这种方式是将私有数据保存在内部存储(设备内存)中,实际上是使用文件流进行读写
    • External Storage:这种方式是将公共数据存储在共享外部存储上;也就是将数据存储在SD卡上,存储在这上面说明数据是开放的,其它应用可以直接访问;这跟上面一种都是平常所说的文件存储
    • SQLite Databases:这种方式是将结构化数据存储在私有数据库中;这也就是常说的数据库存储,使用SQLite保存数据,这些数据是私有的
    • Network Connection:这种方式是将数据存储在Web服务器上,也就是通常所说的网络存储

    笔者上一篇文章讲述了Shared Preferences的工作原理及使用封装,这篇文章来掰掰第二种和第三种方式

    文件存储

    本文所含代码随时更新,可从这里下载最新代码
    传送门Mango

    说到文件存储,就必须说下Android世界中的文件系统了

    大家使用Android手机的时候,多多少少都去过设置->应用界面,选择一个应用打开,可以看到上面有清除数据,清除缓存两个按钮;有的手机可能做的页面不一样了,只有一个清除数据按钮,但是还是能看到列举出来的类型;那你知道这两个按钮是清除的哪里的数据吗?

    我们经常听到内存,内部存储,外部存储这几个概念,那它们分别表示什么呢?我们开发者存储数据的时候应该把数据存储到什么地方呢?

    内存

    内存指的是手机在运行应用程序时需要的存储空间,也称为RAM,即运行内存,这个值基本上在手机出厂后就确定了;当你买手机的时候,销售员跟你说这个手机配备8G内存+128G存储等配置时,这个8G指的就是RAM,也就是应用运行时理论上能利用到的最大内存了;这个有点类似于电脑上的内存条,只不过电脑内存条可以后期增加,理论上这个值越大,基本上手机运行的就越流畅

    内部存储

    英文称为Internal Storage,我们可以将文件直接保存在设备的内部存储中。 默认情况下,保存到内部存储的文件对应用程序是私有的,而其他应用程序无法访问它们(用户也无法访问,除非root),使用内部存储不需要额外的权限; 当用户卸载应用程序时,将删除这些文件;从技术上来讲如果你在创建内部存储文件的时候将文件属性设置成可读,其他app能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,因而显得可贵,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用

    我们开发中经常说某些文件在data目录下,这个data文件夹就是我们常说的内部存储,里面有两个比较重要的子文件夹

    • app文件夹:这里存放应用的apk文件
    • data文件夹:这里有很多以应用包名命名的文件夹,存放着应用数据

    打开其中一个应用文件夹,通常有如下文件

    data/data/包名/shared_prefs //该目录下存放很多SharedPreferences数据,都是一些xml文件
    data/data/包名/databases //该目录下存放db格式的文件,也就是数据库数据
    data/data/包名/files //该目录下存放普通数据
    data/data/包名/cache //该目录下存放缓存文件

    外部存储

    英文称为External Storage,每个Android兼容设备都支持可用于保存文件的共享“外部存储”,它可能是可移除的存储介质(典型如SD卡),也可能是不可移除的存储介质(如现在很多一体机内置的存储器);外部存储是相对于内部存储而言的,不过存储在这上面的文件是所有者可见的,所有人都有权限操作,不过前提是需要申请权限

    要在外部存储上读取或写入文件,您的应用必须获取READ_EXTERNAL_STORAGE或WRITE_EXTERNAL_STORAGE系统权限;如果您需要同时读取和写入文件,则只需要请求WRITE_EXTERNAL_STORAGE权限,因为它也隐式地要求读取权限

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    

    注意:android6.0以后引入了运行时权限的概念,要注意只在AndroidManifest.xml申请是不够的
    注意:从Android 4.4(api19)开始,如果您在外部存储上只读取或写入应用程序专用的文件(即在私有目录读写),则不需要这些权限

    外部存储的最外层目录是storage文件夹,也可能是mnt文件夹,这个根据厂家不同有不同的结果
    一般来说,在storage文件夹中有一个sdcard文件夹,这个文件夹中的文件又分为两类,一类是公共目录,还有一类是私有目录

    • 公共目录:有九大类,比如DCIM、Download、Music、Movies、Pictures、Ringtones等这种系统为我们创建的文件夹;这些目录里的文件所有应用可以分享
    • 私有目录:就是Android这个文件夹,这个文件夹打开之后里边有一个data文件夹,打开这个data文件夹,里边有许多包名组成的文件夹,这个文件夹存放了应用私有数据

    私有目录如下

    storage/sdcard/Android/data/包名/files
    storage/sdcard/Android/data/包名/cache

    经过上面的分析,应该对这些有一个大致的了解了,RAM内存是我们开发的过程中需要注意的,不要内存泄漏,不要无限new内存,因为那样会使得手机运行内存紧张,运行卡顿;通常来说我们很少去操作内部存储空间,因为没有root权限,我们动不了这块,内部存储通常是由系统来维护的,不过在代码中Google还是给了我们API访问这些文件夹

    通常情况下内部存储空间都很有限,在开发中我们操作的最多的还是外部存储,Google官方也建议开发者应该将数据存储在外部存储的私有目录中该APP包名命名的文件夹下,这样某些情况下其它应用是无法对你的应用文件进行写操作;同时当应用被卸载后,相关数据也会被一起清除掉,同时也不会引起用户的反感;如果我们把数据存储在公有目录和storage/sdcard目录下,数据是不会随着应用的卸载而删除的


    内部存储操作

    API

    操作内部存储的api都是Context类的

    • getFilesDir():返回文件系统上特定应用程序的文件目录的绝对路径;返回一个File对象,它的目录是 data/data/包名/files
    • fileList():返回应用程序当前保存的文件数组;返回一个字符串数组,即由data/data/包名/files目录下文件的文件名组成的
    • deleteFile(String name):删除保存在内部存储上的文件;该文件位于data/data/包名/files目录下,返回一个boolean值表示是否删除成功
    • getCacheDir():返回文件系统上应用程序的缓存目录的绝对路径;返回一个File对象,它的目录是 data/data/包名/cache
    • getDir(String name, int mode):在内部存储空间中创建(或打开现有)目录;返回一个File对象;请注意,通过File对象创建的文件只能由您自己的应用程序访问; 您只能设置整个目录的模式,而不能设置单个文件的模式;该文件夹是在data/data/包名 目录上创建的
    • openFileOutput(String name, int mode):打开内部存储中与本应用程序包关联的私有文件以进行写入,如果文件尚不存在,则创建该文件;返回一个输出流FileOutputStream;该文件位于data/data/包名/files目录下
    • openFileInput(String name):打开内部存储中与本应用程序包关联的私有文件以进行读取;返回一个输入流FileInputStream,该文件位于data/data/包名/files目录下

    其中openFileOutput方法第二个参数有如下几个可选值:

    • Context.MODE_PRIVATE:默认模式,创建文件(或替换同名文件),只能由调用程序(或共享相同用户ID的所有应用程序)访问
    • Context.MODE_WORLD_READABLE:允许所有其他应用程序对创建的文件具有读的访问权限,使用这个模式Android N(7.0)开始将抛出SecurityException,这个模式从API17已标记被弃用,创建全局可读文件非常危险,可能引发安全漏洞
    • Context.MODE_WORLD_WRITEABLE:允许所有其他应用程序具有对创建文件的写访问权,,使用这个模式Android N(7.0)开始将抛出SecurityException,这个模式从API17已标记被弃用,创建全局可写文件非常危险,可能引发安全漏洞
    • Context.MODE_APPEND:创建文件,如果文件已存在,则将数据写入现有文件的末尾而不是抹掉它。

    注意:如果您想缓存某些数据,而不是持久存储它们,则应使用getCacheDir()打开一个File,该File表示应用程序应保存临时缓存文件的内部目录;当设备内部存储空间不足时,Android可能会删除这些缓存文件以恢复空间。 但是,您不应该依赖系统来清理这些文件。 您应该始终自己维护缓存文件并保持合理的空间限制,例如1MB。 当用户卸载您的应用程序时,将删除这些文件

    读写操作

    /**
         * 获取文件内容
         * @param fileName 内部存储中文件名
         * @return 按行读取文件内容
         */
        public List<String> getStringFromInternalStorage(String fileName){
    
            List<String> content = new ArrayList<>();
            InputStream is = null;
            BufferedReader br = null;
            try {
                is = mContext.get().openFileInput(fileName);
                br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
                String line ;
                while ( (line = br.readLine()) != null){
                    content.add(line);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
    
                closeInputStream(is);
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            return content;
        }
    
    
        /**
         * 获取内部存储文件数据
         * @param fileName 内部存储中文件名
         * @return 返回文件二进制数据,以便传输
         */
        public byte[] getDataFromInternalStorage(String fileName){
    
            BufferedInputStream bis = null;
            FileInputStream fis = null;
            ByteArrayOutputStream bos = null;
            try {
                fis = mContext.get().openFileInput(fileName);
                bis = new BufferedInputStream(fis);
                bos = new ByteArrayOutputStream();
                byte[] buff = new byte[8*1024];
                int len ;
                while ((len = bis.read(buff)) != -1){
                    bos.write(buff,0,len);
                }
                return bos.toByteArray();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeInputStream(fis);
                closeInputStream(bis);
                closeOutputStream(bos);
            }
            return null;
        }
    
        /**
         * 保存字符串数据到内部存储
         * @param content 保存的内容
         * @param fileName 文件名
         * @param mode 访问模式
         */
        public void putStringToInternalStorage(String content,String fileName,int mode){
    
            FileOutputStream fos = null;
            try {
                fos = mContext.get().openFileOutput(fileName,mode);
                fos.write(content.getBytes());
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(fos);
            }
        }
    
        /**
         * 保存数据到内部存储
         * @param content 保存的内容
         * @param fileName 文件名
         * @param mode 访问模式
         */
        public void putDataToInternalStorage(byte[] content,String fileName,int mode){
    
            FileOutputStream fos = null;
            try {
                fos = mContext.get().openFileOutput(fileName,mode);
                fos.write(content);
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(fos);
            }
        }
    

    外部存储操作

    做外部存储操作之前一定要判断外部存储状态

    /**
         * 判断sd卡是否处于就绪状态 可读可写
         * MEDIA_UNKNOWN:未知状态
         * MEDIA_REMOVED:移除状态(外部存储不存在)
         * MEDIA_UNMOUNTED:未装载状态(外部存储存在但是没有装载)
         * MEDIA_CHECKING:磁盘检测状态
         * MEDIA_NOFS:外部存储存在,但是磁盘为空或使用了不支持的文件系统
         * MEDIA_MOUNTED:就绪状态(可读、可写)
         * MEDIA_MOUNTED_READ_ONLY:只读状态
         * MEDIA_SHARED:共享状态(外部存储存在且正通过USB共享数据)
         * MEDIA_BAD_REMOVAL:异常移除状态(外部存储还没有正确卸载就被移除了)
         * MEDIA_UNMOUNTABLE:不可装载状态(外部存储存在但是无法被装载,一般是磁盘的文件系统损坏造成的)
         * @return
         */
        public boolean isSdCardMount(){
            return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
        }
    

    上面说到外部存储的时候讲到过这里有公共目录和私有目录之分

    公共目录

    通常情况下,用户通过我们的应用获取的比如多媒体文件,像图片、视频、铃声等文件,应该放在这些公共目录中,例如Music /,Pictures /和Ringtones /;将文件保存到相应的媒体类型目录,系统的媒体扫描程序可以正确地对系统中的文件进行分类(例如,铃声在系统设置中显示为铃声,而不是音乐);同时用户可以轻松地从设备找到并复制它们,也能更好的与其它应用分享;即使应用被卸载,这些文件依然保留

    如果要将文件存储在相应的公共目录,可以通过调用getExternalStoragePublicDirectory(String type),向其传递所需的目录类型,例如DIRECTORY_MUSIC,DIRECTORY_PICTURES,DIRECTORY_RINGTONES或其他,参数不可为null,返回一个File对象,如果不存在,即创建

    /**
         * 获取公共目录
         * @param type DIRECTORY_MUSIC 音乐类型
         *             DIRECTORY_RINGTONES 铃声类型
         *             DIRECTORY_PODCASTS 播客音频类型
         *             DIRECTORY_ALARMS 闹钟提示音类型
         *             DIRECTORY_NOTIFICATIONS 通知提示音类型
         *             DIRECTORY_PICTURES 图片类型
         *             DIRECTORY_MOVIES 电影类型
         *             DIRECTORY_DOWNLOADS 下载文件类型
         *             DIRECTORY_DCIM 相机照片类型
         *             DIRECTORY_DOCUMENTS 文档类型
         * @return 相应类型目录文件
         */
        public File getExternalStoragePublicDirectory(String type){
            File file = Environment.getExternalStoragePublicDirectory(type);
            if (!file.exists()) {
                file.mkdir();
            }
            return file;
        }
    

    获取到的目录类似于/storage/sdcard0/Music

    假如不想存放在这些目录里,需要存放在一些自定义的目录中,那就通过Environment.getExternalStorageDirectory()获取外部存储的根目录,通常是SD卡的根目录,比如/storage/sdcard0,然后你就可以在这个目录上新建目录


    私有目录

    私有文件

    如果您正在处理不适合其他应用程序使用的文件(例如仅由您的应用程序使用的文件),则应通过调用getExternalFilesDir()在外部存储上使用专用存储目录。 此方法还接收类型参数来指定子目录的类型(例如DIRECTORY_MOVIES),如果目录不存在Android会创建。 如果您不需要特定的媒体目录,请传递null以接收应用程序私有文件目录的根目录(/storage/sdcard0/Android/data/包名/files/)。

    这在作用上有点类似于内部存储中的getFilesDir()方法,同时都是属于Context的API

    /**
         * 获取私有指定类型目录
         * @param type DIRECTORY_MUSIC 音乐类型
         *             DIRECTORY_PODCASTS 播客音频类型
         *             DIRECTORY_RINGTONES 铃声类型
         *             DIRECTORY_ALARMS 闹钟提示音类型
         *             DIRECTORY_NOTIFICATIONS 通知提示音类型
         *             DIRECTORY_PICTURES 图片类型
         *             DIRECTORY_MOVIES 电影类型
         * @return 相应类型目录文件 例如/storage/sdcard0/Android/data/com.mango.datasave/files/Music
         */
        public File getExternalStoragePrivateDirectory(String type){
            File file = mContext.get().getExternalFilesDir(type);
            return file;
        }
    

    注意:某些移动设备可能既提供了内置存储器作为外部存储空间(通常是手机自带的),同时又提供了SD卡作为外部存储空间。也就是说,在这些设备中外部存储实际上包含了两块磁盘。在Android 4.3(API 18)及以下,Context的getExternalFilesDir方法仅仅会返回内置存储器对应的外部存储空间,而无法访问SD卡对应的存储空间。从Android 4.4(API 19)开始,Context新增了getExternalFilesDirs方法。这个方法的返回值是一个File数组,包含两个对象(可能为null),这样就可以实现对内置存储器和SD卡的访问。数组的第一个对象默认是内置存储器,官方的开发建议是除非这个位置已满或不可用,否则应该使用这个位置

    私有缓存

    同内部存储一样,外部存储也有保存缓存文件的目录,可以通过Context的getExternalCacheDir方法访问缓存文件目录,返回值是一个File对象,对应的目录是 /storage/sdcard0/Android/data/com.mango.datasave/cache ,其中com.mango.datasave是我的测试应用包名;如果目录不存在Android会创建

    如上面的注意点,外部存储可能同时包含内置存储器和SD卡两个存储空间,因此在Android 4.4(API 19)及以上还可以通过Context的getExternalCacheDirs方法访问这两个存储空间。这个方法会返回一个File数组,包含两个对象,第一个对象默认是外部存储内置存储器的缓存文件目录

    File getExternalCacheDir()
    File[] getExternalCacheDirs()
    
    

    注意:当用户卸载您的应用程序时,将删除 /storage/sdcard0/Android/data/包名 目录及其所有内容。 此外,系统扫描程序不读取这些目录中的文件,因此无法从MediaStore内容提供程序访问它们。 因此,您不应将这些目录用于存放属于用户的媒体,例如使用您的应用程序捕获或编辑的照片,或用户使用您的应用程序购买的音乐 - 这些文件应保存在公共目录中

    文件各种操作封装

    /**
     * @Description TODO(文件操作辅助类)
     * @author cxy
     * @Date 2018/10/30 16:26
     */
    public class FileStorageTools {
    
        private String TAG = FileStorageTools.class.getSimpleName();
    
        private WeakReference<Context> mContext ;
        private static FileStorageTools instance;
    
        private FileStorageTools(Context context){
            mContext = new WeakReference<>(context);
        }
        public static FileStorageTools getInstance(Context context){
            if(instance == null){
                instance = new FileStorageTools(context);
            }
            return instance;
        }
    
        //获取ram可用内存
        public String getRAMAvailMem(){
            ActivityManager am=(ActivityManager)mContext.get().getSystemService(Context.ACTIVITY_SERVICE);
            ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
            am.getMemoryInfo(mi);
            return reviseFileSize(mi.availMem);
        }
    
        //获取ram总内存
        public String getRAMTotalMem(){
            ActivityManager am=(ActivityManager)mContext.get().getSystemService(Context.ACTIVITY_SERVICE);
            ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
            am.getMemoryInfo(mi);
            return reviseFileSize(mi.totalMem);
        }
    
        //获取sd卡总大小
        public String getSDTotalSize(){
            if(isSdCardMount()){
                File file=Environment.getExternalStorageDirectory();
                StatFs statFs=new StatFs(file.getPath());
                long blockSize=statFs.getBlockSizeLong();
                long totalBlocks=statFs.getBlockCountLong();
                return reviseFileSize(totalBlocks*blockSize);
            }else {
                return null;
            }
        }
    
        //获取sd卡可用大小
        public String getSDAvailableSize(){
            if(isSdCardMount()){
                File file=Environment.getExternalStorageDirectory();
                StatFs statFs=new StatFs(file.getPath());
                long blockSize=statFs.getBlockSizeLong();
                long availableBlocks=statFs.getFreeBlocksLong();
                return reviseFileSize(availableBlocks*blockSize);
            }else {
                return null;
            }
        }
    
    
        /**================================================内部存储操作=================================================================**/
    
        /**
         * 获取文件内容
         * @param fileName 内部存储中文件名
         * @return 按行读取文件内容
         */
        public List<String> getStringFromInternalStorage(String fileName){
    
            List<String> content = new ArrayList<>();
            InputStream is = null;
            BufferedReader br = null;
            try {
                is = mContext.get().openFileInput(fileName);
                br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
                String line ;
                while ( (line = br.readLine()) != null){
                    content.add(line);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
    
                closeInputStream(is);
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            return content;
        }
    
    
        /**
         * 获取内部存储文件数据
         * @param fileName 内部存储中文件名
         * @return 返回文件二进制数据,以便传输
         */
        public byte[] getDataFromInternalStorage(String fileName){
    
            BufferedInputStream bis = null;
            FileInputStream fis = null;
            ByteArrayOutputStream bos = null;
            try {
                fis = mContext.get().openFileInput(fileName);
                bis = new BufferedInputStream(fis);
                bos = new ByteArrayOutputStream();
                byte[] buff = new byte[8*1024];
                int len ;
                while ((len = bis.read(buff)) != -1){
                    bos.write(buff,0,len);
                }
                return bos.toByteArray();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeInputStream(fis,bis);
                closeOutputStream(bos);
            }
            return null;
        }
    
        /**
         * 保存字符串数据到内部存储
         * @param content 保存的内容
         * @param fileName 文件名
         * @param mode 访问模式
         */
        public void putStringToInternalStorage(String content,String fileName,int mode){
    
            FileOutputStream fos = null;
            try {
                fos = mContext.get().openFileOutput(fileName,mode);
                fos.write(content.getBytes());
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(fos);
            }
        }
    
        /**
         * 保存数据到内部存储
         * @param content 保存的内容
         * @param fileName 文件名
         * @param mode 访问模式
         */
        public void putDataToInternalStorage(byte[] content,String fileName,int mode){
    
            FileOutputStream fos = null;
            try {
                fos = mContext.get().openFileOutput(fileName,mode);
                fos.write(content);
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(fos);
            }
        }
    
        /**
         * 将内容保存到内部存储的缓存目录 尽量别将文件保存在这里,内存有限
         * @param content
         * @param fileName
         * @param append 是否追加到文件尾部
         */
        public void putInternalStorageCache(String content,String fileName,boolean append){
    
            FileOutputStream fos = null;
            try {
                File cache = new File(mContext.get().getCacheDir(),fileName);
                fos = new FileOutputStream(cache,append);
                fos.write(content.getBytes());
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(fos);
            }
        }
    
        /**====================================================外部存储操作=======================================================**/
    
        /**====================================构建目录=================================================**/
    
        /**
         * 获取公共目录
         * @param type DIRECTORY_MUSIC 音乐类型
         *             DIRECTORY_RINGTONES 铃声类型
         *             DIRECTORY_PODCASTS 播客音频类型
         *             DIRECTORY_ALARMS 闹钟提示音类型
         *             DIRECTORY_NOTIFICATIONS 通知提示音类型
         *             DIRECTORY_PICTURES 图片类型
         *             DIRECTORY_MOVIES 电影类型
         *             DIRECTORY_DOWNLOADS 下载文件类型
         *             DIRECTORY_DCIM 相机照片类型
         *             DIRECTORY_DOCUMENTS 文档类型
         * @return 相应类型目录文件 例如/storage/sdcard0/Music
         */
        public File getExternalStoragePublicDirectory(String type){
            File file = Environment.getExternalStoragePublicDirectory(type);
            if (!file.exists()) {
                file.mkdir();
            }
            return file;
        }
    
        /**
         * 获取私有文件目录
         * @param type DIRECTORY_MUSIC 音乐类型
         *             DIRECTORY_PODCASTS 播客音频类型
         *             DIRECTORY_RINGTONES 铃声类型
         *             DIRECTORY_ALARMS 闹钟提示音类型
         *             DIRECTORY_NOTIFICATIONS 通知提示音类型
         *             DIRECTORY_PICTURES 图片类型
         *             DIRECTORY_MOVIES 电影类型
         * @return 相应类型目录文件 例如/storage/sdcard0/Android/data/com.mango.datasave/files/Music
         */
        public File getExternalStoragePrivateDirectory(String type){
            File file = mContext.get().getExternalFilesDir(type);
            return file;
        }
    
        /**
         * 获取私有缓存目录
         * @return /storage/sdcard0/Android/data/com.mango.datasave/cache
         */
        public File getExternalStoragePrivateCache(){
            File file = mContext.get().getExternalCacheDir();
            return file;
        }
    
        /**
         * 构建文件目录
         * @param path 例如 /file/movie
         * @return 返回完整目录 /storage/sdcard0/file/movie
         */
        public String makeFilePath(String path){
            if (StringTools.isEmpty(path)) throw new NullPointerException("path cant be null");
            return Environment.getExternalStorageDirectory().getAbsolutePath() + path;
        }
    
    
        /**
         * 创建文件
         * @param base
         * @param fileName
         * @return
         */
        public File makeFile(File base,String fileName){
            if (StringTools.isEmpty(fileName)) throw new NullPointerException("fileName cant be null");
            if(fileName.indexOf(File.separator) < 0){
                return new File(base,fileName);
            }
            throw new IllegalArgumentException(
                    "File " + fileName + " contains a path separator");
        }
    
        /**====================================保存数据=================================================**/
    
        /**
         * 将内容写到外部存储文件
         * @param content 内容
         * @param parent 目标文件父目录
         * @param fileName 文件名
         * @param append 内容是追加到文件末尾还是覆盖
         */
        public void putStringToExternalStorage(String content,File parent, String fileName,boolean append){
    
            FileOutputStream fos = null;
    
            File file = makeFile(parent,fileName);
            try {
                fos = new FileOutputStream(file,append);
                fos.write(content.getBytes());
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(fos);
            }
        }
    
        /**
         * 将内容写到外部存储文件
         * @param parent 目标文件父目录
         * @param fileName 文件名
         * @param content 内容
         *                @String.getBytes()
         */
        public void putDataToExternalStorage(File parent, String fileName,byte[] content){
    
            FileOutputStream fos = null;
            try {
                File file = makeFile(parent,fileName);
                fos = new FileOutputStream(file);
                fos.write(content);
                fos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(fos);
            }
        }
    
        /**
         * 将流数据保存到外部存储文件
         * @param parent 目标文件父目录
         * @param fileName 文件名
         * @param is 流
         */
        public void putStreamToExternalStorage(File parent, String fileName,InputStream is){
    
            BufferedOutputStream bos = null;
            BufferedInputStream bis = null;
    
            try {
                File file = makeFile(parent,fileName);
                bis = new BufferedInputStream(is);
                bos = new BufferedOutputStream(new FileOutputStream(file));
                byte[] buff = new byte[8*1024];
                int len;
                while ( (len = bis.read(buff)) != -1) {
                    bos.write(buff,0,len);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeInputStream(is,bis);
                closeOutputStream(bos);
            }
    
        }
    
        /**
         * 将bitmap保存到外部存储文件
         * @param parent 目标文件父目录
         * @param fileName 文件名
         * @param bitmap 图片
         */
        public void putBitmapToExternalStorage(File parent, String fileName, Bitmap bitmap){
    
            BufferedOutputStream bos = null;
    
            File bit = makeFile(parent,fileName);
            try {
                bos = new BufferedOutputStream(new FileOutputStream(bit));
                if (fileName.contains(".png") || fileName.contains(".PNG")) {
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
                } else {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
                }
                bos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeOutputStream(bos);
            }
    
        }
    
    
        /**====================================读取数据=================================================**/
    
        /**
         * 读取外部文件数据
         * @param path 文件路径
         * @return 文件的字节数组
         */
        public byte[] getDataFromExternalStorage(String path){
    
            byte[] data = null;
            File file = new File(path);
            if (!file.exists()) return null;
    
            BufferedInputStream bis = null;
            ByteArrayOutputStream bos = null;
            try {
                bis = new BufferedInputStream(new FileInputStream(file));
                bos = new ByteArrayOutputStream();
                byte[] buff = new byte[8*1024];
                int len;
                while ((len = bis.read(buff)) != -1) {
                    bos.write(buff,0,len);
                }
                data = bos.toByteArray();
                bos .flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeInputStream(bis);
                closeOutputStream(bos);
            }
            return data;
        }
    
        /**
         * 按行读取文件内容
         * @param path 文件路径
         * @return
         */
        public List<String> getStringFromExternalStorage(String path){
    
            File file = new File(path);
            if (!file.exists()) return null;
    
            List<String> data = new ArrayList<>();
            InputStreamReader isr = null;
            BufferedReader br = null;
            try {
                isr = new InputStreamReader(new FileInputStream(file),"utf-8");
                br = new BufferedReader(isr);
                data.add(br.readLine());
                isr.close();
                br.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return data;
        }
    
        /**====================================文件拷贝操作=================================================**/
    
        /**
         * 单个文件复制
         * @param oldFile 原文件目录
         * @param newFile 新文件
         */
        public void copyFile(String oldFile,File newFile){
    
            File oldF = new File(oldFile);
            if(!oldF.exists()) return;
    
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try {
                fis = new FileInputStream(oldF);
                fos = new FileOutputStream(newFile);
                byte[] buff = new byte[8*1024];
                int len;
                while ((len = fis.read(buff)) != -1) {
                    fos.write(buff,0,len);
                }
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeInputStream(fis);
                closeOutputStream(fos);
            }
        }
    
        /**====================================资源文件操作=================================================**/
    
       /**
         * 获取raw目录下文件数据流 调用 getDataFromRaw(R.raw.mango)
         * @param resourceID R.raw.mango
         * @return
         */
        public InputStream getStreamFromRaw(int resourceID){
    
            InputStream in = null;
            try {
                in = mContext.get().getResources().openRawResource(resourceID);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return in;
        }
    
        /**
         * 获取assert目录下文件数据流
         * 调用getDataFromAssets("mango.txt")
         * 如果多层目录就要带上父级目录 getStreamFromAssets("today/day.txt")
         * @param fileName 文件全名,包括后缀
         * @return 数据流
         */
        public InputStream getStreamFromAssets(String fileName){
            InputStream in = null;
            try {
                in = mContext.get().getResources().getAssets().open(fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return in;
        }
    
        /**
         * 从资源目录下读取数据
         * @param is 数据流
         * @return
         */
        public byte[] getDataFromResource(InputStream is){
    
            if(is == null) return null;
    
            try {
                int lenght = is.available();
                byte[]  buffer = new byte[lenght];
                //将文件中的数据读到byte数组中
                is.read(buffer);
                is.close();
                return buffer;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 将资源文件拷贝到外部存储
         * @param file 输出目标文件
         * @param is 资源文件流
         */
        public  void moveResourceFileToExternalStorage(File file, InputStream is){
    
            if(is == null) return;
            FileOutputStream os = null;
            try {
                os = new FileOutputStream(file);
                byte[] buffer = new byte[2*1024];
                int len;
                while ((len = is.read(buffer)) != -1){
                    os.write(buffer, 0, len);
                }
                os.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                closeInputStream(is);
                closeOutputStream(os);
            }
    
        }
    
    
        /**====================================文件普通操作=================================================**/
    
    	private List<File> fList = new ArrayList<>();
    
        public void clearFlist(){
            fList.clear();
        }
       
        /**
         * 给文件重命名
         * @param oldPath 原文件
         * @param newPath 新文件
         * @return
         */
        public boolean renameFile(String oldPath,String newPath){
            File oldFile = new File(oldPath);
            File newFile = new File(newPath);
            return oldFile.renameTo(newFile);
        }
    
        /**
         * 遍历目录
         * @param path 文件夹目录
         * @return
         */
        public List<File> listFile(String path){
    
            File file = new File(path);
            if (!file.exists()) {
                return null;
            }
            File[] data = file.listFiles();
            if(data == null) return null;
    
            for(int i=0; i<data.length; i++){
                File child = data[i];
                if (child.isFile()) {
                    fList.add(child);
                } else {
                    listFile(child.getAbsolutePath());
                }
            }
            return fList;
        }
    
        /**
         *
         * @param path
         */
        public void delFile(String path){
    
            List<File> file = listFile(path);
            if(file == null)return;
            for(int i=0; i<file.size(); i++){
                file.get(i).delete();
            }
        }
    
        /**
         * 获取文件的文件名(不包括扩展名)
         */
        public String getFileNameWithoutExtension(String path) {
            if(path == null) {
                return null;
            }
            int separatorIndex = path.lastIndexOf(File.separator);
            if(separatorIndex < 0) {
                separatorIndex = 0;
            }
            int dotIndex = path.lastIndexOf(".");
            if(dotIndex < 0) {
                dotIndex = path.length();
            } else if(dotIndex < separatorIndex) {
                dotIndex = path.length();
            }
            return path.substring(separatorIndex + 1, dotIndex);
        }
    
        /**
         * 获取文件名
         */
        public String getFileName(String path) {
            if(path == null) {
                return null;
            }
            int separatorIndex = path.lastIndexOf(File.separator);
            return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
        }
    
    
        public void closeInputStream(InputStream... is){
    
            for (int i=0; i<is.length; i++){
                if (is[i] != null) {
                    try {
                        is[i].close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    
        public void closeOutputStream(OutputStream... os){
    
            for (int i=0; i<os.length; i++){
                if (os[i] != null) {
                    try {
                        os[i].close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    
        /**
         * 判断sd卡是否处于就绪状态 可读可写
         * MEDIA_UNKNOWN:未知状态
         * MEDIA_REMOVED:移除状态(外部存储不存在)
         * MEDIA_UNMOUNTED:未装载状态(外部存储存在但是没有装载)
         * MEDIA_CHECKING:磁盘检测状态
         * MEDIA_NOFS:外部存储存在,但是磁盘为空或使用了不支持的文件系统
         * MEDIA_MOUNTED:就绪状态(可读、可写)
         * MEDIA_MOUNTED_READ_ONLY:只读状态
         * MEDIA_SHARED:共享状态(外部存储存在且正通过USB共享数据)
         * MEDIA_BAD_REMOVAL:异常移除状态(外部存储还没有正确卸载就被移除了)
         * MEDIA_UNMOUNTABLE:不可装载状态(外部存储存在但是无法被装载,一般是磁盘的文件系统损坏造成的)
         * @return
         */
        public boolean isSdCardMount(){
            return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
        }
    
    
        public String reviseFileSize(long size){
            String str="KB";
            float reviseSize = 0f;
            if(size>1024){
                reviseSize = size/1024f;
                if(reviseSize>1024){
                    str="M";
                    reviseSize = reviseSize/1024f;
                    if (reviseSize>1024) {
                        str="G";
                        reviseSize = reviseSize/1024f;
                    }
                }
            }
    
            DecimalFormat formatter=new DecimalFormat();
            formatter.setGroupingSize(3);
            String result = formatter.format(reviseSize) + str;
            return result;
        }
    
    }
    

    后续文件其它操作再陆续补充

    展开全文
  • Oracle 存储过程异常处理

    万次阅读 2011-07-05 15:29:45
    1、异常的优点     如果没有异常,在程序中,应当检查每个命令的成功还是失败,如   BEGIN   SELECT ...   -- check for ’no data found’ error   SELECT ...   -- check f

    1、异常的优点 
       
      如果没有异常,在程序中,应当检查每个命令的成功还是失败,如 
      BEGIN 
      SELECT ... 
      -- check for ’no data found’ error 
      SELECT ... 
      -- check for ’no data found’ error 
      SELECT ... 
      -- check for ’no data found’ error 
      这种实现的方法缺点在于错误处理没有与正常处理分开,可读性差,使用异常,可以方便处理错误,而且异常处理程序与正常的事务逻辑分开,提高了可读性,如 
      BEGIN 
      SELECT ... 
      SELECT ... 
      SELECT ... 
      ... 
      EXCEPTION 
      WHEN NO_DATA_FOUND THEN -- catches all ’no data found’ errors 
       
      2、异常的分类 
       
      有两种类型的异常,一种为内部异常,一种为用户自定义异常,内部异常是执行期间返回到PL/SQL块的ORACLE错误或由PL/SQL代码的某操作引起的错误,如除数为零或内存溢出的情况。用户自定义异常由开发者显示定义,在PL/SQL块中传递信息以控制对于应用的错误处理。 
       
      每当PL/SQL违背了ORACLE原则或超越了系统依赖的原则就会隐式的产生内部异常。因为每个ORACLE错误都有一个号码并且在PL/SQL中异常通过名字处理,ORACLE提供了预定义的内部异常。如SELECT INTO 语句不返回行时产生的ORACLE异常NO_DATA_FOUND。对于预定义异常,现将最常用的异常列举如下: 
      exception  oracle error  sqlcode value  condition 
      no_data_found              ora-01403  +100  select into 语句没有符合条件的记录返回 
      too_many_rows  ora-01422  -1422  select into 语句符合条件的记录有多条返回 
      dup_val_on_index  ora-00001  -1  对于数据库表中的某一列,该列已经被限制为唯一索引,程序试图存储两个重复的值 
      value_error  ora-06502  -6502  在转换字符类型,截取或长度受限时,会发生该异常,如一个字符分配给一个变量,而该变量声明的长度比该字符短,就会引发该异常 
      storage_error  ora-06500  -6500  内存溢出 
      zero_divide  ora-01476  -1476  除数为零 
      case_not_found  ora-06592  -6530  对于选择case语句,没有与之相匹配的条件,同时,也没有else语句捕获其他的条件 
      cursor_already_open  ora-06511  -6511  程序试图打开一个已经打开的游标 
      timeout_on_resource  ora-00051  -51  系统在等待某一资源,时间超时 
       
      如果要处理未命名的内部异常,必须使用OTHERS异常处理器或PRAGMA EXCEPTION_INIT 。PRAGMA由编译器控制,或者是对于编译器的注释。PRAGMA在编译时处理,而不是在运行时处理。EXCEPTION_INIT告诉编译器将异常名与ORACLE错误码结合起来,这样可以通过名字引用任意的内部异常,并且可以通过名字为异常编写一适当的异常处理器。 
       
      在子程序中使用EXCEPTION_INIT的语法如下: 
      PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number); 
       
      在该语法中,异常名是声明的异常,下例是其用法: 
      DECLARE 
      deadlock_detected EXCEPTION; 
      PRAGMA EXCEPTION_INIT(deadlock_detected, -60); 
      BEGIN 
      ... -- Some operation that causes an ORA-00060 error 
      EXCEPTION 
      WHEN deadlock_detected THEN 
      -- handle the error 
      END; 
       
      对于用户自定义异常,只能在PL/SQL块中的声明部分声明异常,异常的名字由EXCEPTION关键字引入: 
      reserved_loaned Exception 
       
      产生异常后,控制传给了子程序的异常部分,将异常转向各自异常控制块,必须在代码中使用如下的结构处理错误: 
      Exception 
      When exception1 then 
      Sequence of statements; 
      When exception2 then 
      Sequence of statements; 
      When others then 
       
      3、异常的抛出 
       
      由三种方式抛出异常 
       
      1. 通过PL/SQL运行时引擎 
       
      2. 使用RAISE语句 
       
      3. 调用RAISE_APPLICATION_ERROR存储过程 
       
      当数据库或PL/SQL在运行时发生错误时,一个异常被PL/SQL运行时引擎自动抛出。异常也可以通过RAISE语句抛出 
      RAISE exception_name; 
       
      显式抛出异常是程序员处理声明的异常的习惯用法,但RAISE不限于声明了的异常,它可以抛出任何任何异常。例如,你希望用TIMEOUT_ON_RESOURCE错误检测新的运行时异常处理器,你只需简单的在程序中使用下面的语句: 
      RAISE TIMEOUT_ON_RESOUCE; 
       
      比如下面一个订单输入的例子,若当订单小于库存数量,则抛出异常,并且捕获该异常,处理异常 
      DECLARE 
      inventory_too_low EXCEPTION; 
       
      ---其他声明语句 
      BEGIN 
      IF order_rec.qty>inventory_rec.qty THEN 
      RAISE inventory_too_low; 
      END IF 
      EXCEPTION 
      WHEN inventory_too_low THEN 
      order_rec.staus:='backordered'; 
      END; 
       
      RAISE_APPLICATION_ERROR内建函数用于抛出一个异常并给异常赋予一个错误号以及错误信息。自定义异常的缺省错误号是+1,缺省信息是User_Defined_Exception。RAISE_APPLICATION_ERROR函数能够在pl/sql程序块的执行部分和异常部分调用,显式抛出带特殊错误号的命名异常。  Raise_application_error(error_number,message[,true,false])) 
       
      错误号的范围是-20,000到-20,999。错误信息是文本字符串,最多为2048字节。TRUE和FALSE表示是添加(TRUE)进错误堆(ERROR STACK)还是覆盖(overwrite)错误堆(FALSE)。缺省情况下是FALSE。 
       
      如下代码所示: 
      IF product_not_found THEN 
      RAISE_APPLICATION_ERROR(-20123,'Invald product code' TRUE); 
      END IF; 
       
      4、异常的处理 
       
      PL/SQL程序块的异常部分包含了程序处理错误的代码,当异常被抛出时,一个异常陷阱就自动发生,程序控制离开执行部分转入异常部分,一旦程序进入异常部分就不能再回到同一块的执行部分。下面是异常部分的一般语法: 
      EXCEPTION 
      WHEN exception_name THEN 
      Code for handing exception_name 
      [WHEN another_exception THEN 
      Code for handing another_exception] 
      [WHEN others THEN 
      code for handing any other exception.] 
       
      用户必须在独立的WHEN子串中为每个异常设计异常处理代码,WHEN OTHERS子串必须放置在最后面作为缺省处理器处理没有显式处理的异常。当异常发生时,控制转到异常部分,ORACLE查找当前异常相应的WHEN..THEN语句,捕捉异常,THEN之后的代码被执行,如果错误陷阱代码只是退出相应的嵌套块,那么程序将继续执行内部块END后面的语句。如果没有找到相应的异常陷阱,那么将执行WHEN OTHERS。在异常部分WHEN 子串没有数量限制。 
      EXCEPTION 
      WHEN inventory_too_low THEN 
      order_rec.staus:='backordered'; 
      replenish_inventory(inventory_nbr=> 
      inventory_rec.sku,min_amount=>order_rec.qty-inventory_rec.qty); 
      WHEN discontinued_item THEN 
      --code for discontinued_item processing 
      WHEN zero_divide THEN 
      --code for zero_divide 
      WHEN OTHERS THEN 
      --code for any other exception 
      END; 
       
      当异常抛出后,控制无条件转到异常部分,这就意味着控制不能回到异常发生的位置,当异常被处理和解决后,控制返回到上一层执行部分的下一条语句。 
      BEGIN 
      DECLARE 
      bad_credit exception; 
      BEGIN 
      RAISE bad_credit; 
      --发生异常,控制转向; 
      EXCEPTION 
      WHEN bad_credit THEN 
      dbms_output.put_line('bad_credit'); 
      END; 
      --bad_credit异常处理后,控制转到这里 
      EXCEPTION 
      WHEN OTHERS THEN 
       
      --控制不会从bad_credit异常转到这里 
       
      --因为bad_credit已被处理 
       
      END; 
       
      当异常发生时,在块的内部没有该异常处理器时,控制将转到或传播到上一层块的异常处理部分。 
       
      BEGIN 
      DECLARE ---内部块开始 
       
      bad_credit exception; 
      BEGIN 
      RAISE bad_credit; 
       
      --发生异常,控制转向; 
      EXCEPTION 
      WHEN ZERO_DIVIDE THEN --不能处理bad_credite异常 
      dbms_output.put_line('divide by zero error'); 
       
      END --结束内部块 
       
      --控制不能到达这里,因为异常没有解决; 
       
      --异常部分 
       
      EXCEPTION 
      WHEN OTHERS THEN 
      --由于bad_credit没有解决,控制将转到这里 
      END; 
       
      5、异常的传播 
       
      没有处理的异常将沿检测异常调用程序传播到外面,当异常被处理并解决或到达程序最外层传播停止。在声明部分抛出的异常将控制转到上一层的异常部分。 
       
      BEGIN 
      executable statements 
      BEGIN 
      today DATE:='SYADATE'; --ERRROR 
       
      BEGIN --内部块开始 
      dbms_output.put_line('this line will not execute'); 
      EXCEPTION 
      WHEN OTHERS THEN 
       
      --异常不会在这里处理 
       
      END;--内部块结束 
      EXCEPTION 
      WHEN OTHERS THEN 
       
      处理异常 
       
      END


    -------------------------------------------------------------------------------------------------------------------------
    -------------------------------------------------------------------------------------------------------------------------


    处理 oracle 系统自动生成系统异常外,可以使用 raise 来手动生成错误。

    l         Raise exception;

    l         Raise package.exception;

    l         Raise;

    以上是 raise 的三种使用方法。第一种用于生成当前程序中定义的异常或在 standard 中的系统异常。

           Declare

                  Invalid_id exception;

                  Id_values varchar(2);

           Begin

                  Id_value:=id_for(‘smith’);

                  If substr(id_value,1,1)!=’x’

                  Then

                         Raise invalid_id;

                  End if;

           Exception

                  When invalid_id

                  Then

                         Dbms_output.put_line(‘this is an invalid id!’);

           End;

    这是一个生成自定义异常的例子,当然也可以生成系统异常:

           declare

                  employee_id_in number;

           Begin

    Select employee_id into employee_id_in from employ_list where employee_name=&n;

    If employee_id_in=0

    Then

           Raise zero_devided;

    End if;

           Exception

                  When zero_devided

                  Then

                         Dbms_output.put_line(‘wrong!’);

           End;

    有一些异常是定义在非标准包中的,如 UTL_FILE , DBMS_SQL 以及程序员创建的包中异常。可以使用 raise 的第二种用法来生成异常。

           If day_overdue(isbn_in, browser_in) > 365

           Then

                  Raise overdue_pkg.book_is_lost

           End if;

    在最后一种 raise 的形式中,不带任何参数。这种情况只出现在希望将当前的异常传到外部程序时。

           Exception

                  When no_data_found

                  Then

                         Raise;

           End;

     

    Pl.sql 使用 raise_application_error 过程来生成一个有具体描述的异常。当使用这个过程时,当前程序被中止,输入输出参数被置为原先的值,但任何 DML 对数据库所做的改动将被保留,可以在之后用 rollback 命令回滚。下面是该过程的原型:

           Procedure raise_application_error(

           Num binary_integer;

           Msg varchar2;

           Keeperrorstack Boolean default false

    )

    其中 num 是在 -20999 到 -20000 之间的任何数字(但事实上, DBMS_OUPUT 和 DBMS_DESCRIBLE 包使用了 -20005 到 -20000 的数字); msg 是小于 2K 个字符的描述语,任何大于 2K 的字符都将被自动丢弃; keeperrorstack 默认为 false ,是指清空异常栈,再将当前异常入栈,如果指定 true 的话就直接将当前异常压入栈中。

        CREATE OR REPLACE PROCEDURE raise_by_language (code_in IN PLS_INTEGER)

        IS

           l_message error_table.error_string%TYPE;

        BEGIN

           SELECT error_string

             INTO l_message

             FROM error_table, v$nls_parameters v

            WHERE error_number = code_in

              AND string_language = v.VALUE

              AND v.parameter = 'NLS_LANGUAGE';

     

           RAISE_APPLICATION_ERROR (code_in, l_message);

        END;



    ORACL内部异常:

    ORA-00001: 违反唯一约束条件 (.) 
    ORA-00017: 请求会话以设置跟踪事件 
    ORA-00018: 超出最大会话数 
    ORA-00019: 超出最大会话许可数 
    ORA-00020: 超出最大进程数 () 
    ORA-00021: 会话附属于其它某些进程;无法转换会话 
    ORA-00022: 无效的会话 ID;访问被拒绝 
    ORA-00023: 会话引用进程私用内存;无法分离会话 
    ORA-00024: 单一进程模式下不允许从多个进程注册 
    ORA-00025: 无法分配  
    ORA-00026: 丢失或无效的会话 ID 
    ORA-00027: 无法删去当前会话 
    ORA-00028: 您的会话己被删去 
    ORA-00029: 会话不是用户会话 
    ORA-00030: 用户会话 ID 不存在。 
    ORA-00031: 标记要删去的会话 
    ORA-00032: 无效的会话移植口令 
    ORA-00033: 当前的会话具有空的移植口令 
    ORA-00034: 无法在当前 PL/SQL 会话中  
    ORA-00035: LICENSE_MAX_USERS 不能小于当前用户数 
    ORA-00036: 超过递归 SQL () 级的最大值 
    ORA-00037: 无法转换到属于不同服务器组的会话 
    ORA-00038: 无法创建会话: 服务器组属于其它用户 
    ORA-00050: 获取入队时操作系统出错 
    ORA-00051: 等待资源超时 
    ORA-00052: 超出最大入队资源数 () 
    ORA-00053: 超出最大入队数 
    ORA-00054: 资源正忙,要求指定 NOWAIT 
    ORA-00055: 超出 DML 锁的最大数 
    ORA-00056: 对象 '.' 上的 DDL 锁以不兼容模式挂起 
    ORA-00057: 超出临时表锁的最大数 
    ORA-00058: DB_BLOCK_SIZE 必须为才可安装此数据库 (非 ) 
    ORA-00059: 超出 DB_FILES 的最大值 
    ORA-00060: 等待资源时检测到死锁 
    ORA-00061: 另一个例程设置了不同的 DML_LOCKS 
    ORA-00062: 无法获得 DML 全表锁定;DML_LOCKS 为 0 
    ORA-00063: 超出 LOG_FILES 的最大数 
    ORA-00064: 对象过大以至无法分配在此 O/S (,) 
    ORA-00065: FIXED_DATE 的初始化失败 
    ORA-00066: LOG_FILES 为  但需要成为  才可兼容 
    ORA-00067: 值  对参数  无效;至少必须为  
    ORA-00068: 值  对参数  无效,必须在  和  之间 
    ORA-00069: 无法获得锁定 -- 禁用了表锁定 
    ORA-00070: 命令无效 
    ORA-00071: 进程号必须介于 1 和  之间 
    ORA-00072: 进程""不活动 
    ORA-00073: 命令  介于  和  个参数之间时使用 
    ORA-00074: 未指定进程 
    ORA-00075: 在此例程未找到进程 "" 
    ORA-00076: 未找到转储  
    ORA-00077: 转储  无效 
    ORA-00078: 无法按名称转储变量 
    ORA-00079: 未找到变量  
    ORA-00080: 层次  指定的全局区域无效 
    ORA-00081: 地址范围 [,) 不可读 
    ORA-00082:  的内存大小不在有效集合 [1], [2], [4] 之内 
    ORA-00083: 警告: 可能损坏映射的 SGA  
    ORA-00084: 全局区域必须为 PGA, SGA 或 UGA 
    ORA-00085: 当前调用不存在 
    ORA-00086: 用户调用不存在 
    ORA-00087: 命令无法在远程例程上执行 
    ORA-00088: 共享服务器无法执行命令 
    ORA-00089: ORADEBUG 命令中无效的例程号 
    ORA-00090: 未能将内存分配给群集数据库 ORADEBUG 命令 
    ORA-00091: LARGE_POOL_SIZE 至少必须为  
    ORA-00092: LARGE_POOL_SIZE 必须大于 LARGE_POOL_MIN_ALLOC 
    ORA-00093:  必须介于  和  之间 
    ORA-00094:  要求整数值 
    ORA-00096: 值  对参数  无效,它必须来自  之间 
    ORA-00097: 使用 Oracle SQL 特性不在 SQL92  级中 
    ORA-00099: 等待资源时发生超时,可能是 PDML 死锁所致 
    ORA-00100: 未找到数据 
    ORA-00101: 系统参数 DISPATCHERS 的说明无效 
    ORA-00102: 调度程序无法使用网络协议  
    ORA-00103: 无效的网络协议;供调度程序备用 
    ORA-00104: 检测到死锁;全部公用服务器已锁定等待资源 
    ORA-00105: 未配置网络协议  的调度机制 
    ORA-00106: 无法在连接到调度程序时启动/关闭数据库 
    ORA-00107: 无法连接到 ORACLE 监听器进程 
    ORA-00108: 无法设置调度程序以同步进行连接 
    ORA-00111: 由于服务器数目限制在 , 所以没有启动所有服务器 
    ORA-00112: 仅能创建多达  (最多指定) 个调度程序 
    ORA-00113: 协议名  过长 
    ORA-00114: 缺少系统参数 SERVICE_NAMES 的值 
    ORA-00115: 连接被拒绝;调度程序连接表已满 
    ORA-00116: SERVICE_NAMES 名过长 
    ORA-00117: 系统参数 SERVICE_NAMES 的值超出范围 
    ORA-00118: 系统参数 DISPATCHERS 的值超出范围 
    ORA-00119: 系统参数  的说明无效 
    ORA-00120: 未启用或安装调度机制 
    ORA-00121: 在缺少 DISPATCHERS 的情况下指定了 SHARED_SERVERS 
    ORA-00122: 无法初始化网络配置 
    ORA-00123: 空闲公用服务器终止 
    ORA-00124: 在缺少 MAX_SHARED_SERVERS 的情况下指定了 DISPATCHERS 
    ORA-00125: 连接被拒绝;无效的演示文稿 
    ORA-00126: 连接被拒绝;无效的重复 
    ORA-00127: 调度进程  不存在 
    ORA-00128: 此命令需要调度进程名 
    ORA-00129: 监听程序地址验证失败 '' 
    ORA-00130: 监听程序地址 '' 无效 
    ORA-00131: 网络协议不支持注册 '' 
    ORA-00132: 语法错误或无法解析的网络名称 '' 
    ORA-00150: 重复的事务处理 ID 
    ORA-00151: 无效的事务处理 ID 
    ORA-00152: 当前会话与请求的会话不匹配 
    ORA-00153: XA 库中的内部错误 
    ORA-00154: 事务处理监视器中的协议错误 
    ORA-00155: 无法在全局事务处理之外执行工作 
    ORA-00160: 全局事务处理长度  超出了最大值 () 
    ORA-00161: 事务处理的分支长度  非法 (允许的最大长度为 ) 
    ORA-00162: 外部 dbid 的长度  超出了最大值 () 
    ORA-00163: 内部数据库名长度  超出了最大值 () 
    ORA-00164: 在分布式事务处理中不允许独立的事务处理 
    ORA-00165: 不允许对远程操作进行可移植分布式自治转换 
    ORA-00200: 无法创建控制文件 
    ORA-00201: 控制文件版本  与 ORACLE 版本  不兼容 
    ORA-00202: 控制文件: '' 
    ORA-00203: 使用错误的控制文件 
    ORA-00204: 读控制文件时出错 (块 ,# 块 ) 
    ORA-00205: 标识控制文件出错,有关详情,请检查警告日志 
    ORA-00206: 写控制文件时出错 (块 ,# 块 ) 
    ORA-00207: 控制文件不能用于同一数据库 
    ORA-00208: 控制文件的名称数超出限制  
    ORA-00209: 控制文件块大小不匹配,有关详情,请检查警告日志 
    ORA-00210: 无法打开指定的控制文件 
    ORA-00211: 控制文件与先前的控制文件不匹配 
    ORA-00212: 块大小  低于要求的最小大小 ( 字节) 
    ORA-00213: 不能重新使用控制文件;原文件大小为 ,还需  
    ORA-00214: 控制文件 '' 版本  与文件 '' 版本  不一致 
    ORA-00215: 必须至少存在一个控制文件 
    ORA-00216: 无法重新调整从 8.0.2 移植的控制文件大小 
    ORA-00217: 从 9.0.1 进行移植无法重新调整控制文件的大小 
    ORA-00218: 控制文件的块大小  与 DB_BLOCK_SIZE () 不匹配 
    ORA-00219: 要求的控制文件大小  超出了允许的最大值  
    ORA-00220: 第一个例程未安装控制文件,有关详情,请检查警告日志 
    ORA-00221: 写入控制文件出错 
    ORA-00222: 操作将重新使用当前已安装控制文件的名称 
    ORA-00223: 转换文件无效或版本不正确 
    ORA-00224: 控制文件重设大小尝试使用非法记录类型 () 
    ORA-00225: 控制文件的预期大小  与实际大小  不同 
    ORA-00226: 备用控制文件打开时不允许进行操作 
    ORA-00227: 控制文件中检测到损坏的块: (块 ,# 块 ) 
    ORA-00228: 备用控制文件名长度超出了最大长度  
    ORA-00229: 操作不允许: 已挂起快照控制文件入队 
    ORA-00230: 操作不允许: 无法使用快照控制文件入队 
    ORA-00231: 快照控制文件未命名 
    ORA-00232: 快照控制文件不存在, 已损坏或无法读取 
    ORA-00233: 控制文件副本已损坏或无法读取 
    ORA-00234: 标识或打开快照或复制控制文件时出错 
    ORA-00235: 控制文件固定表因并发更新而不一致 
    ORA-00236: 快照操作不允许: 挂上的控制文件为备份文件 
    ORA-00237: 快照操作不允许: 控制文件新近创建 
    ORA-00238: 操作将重用属于数据库一部分的文件名 
    ORA-00250: 未启动存档器 
    ORA-00251: LOG_ARCHIVE_DUPLEX_DEST 不能是与字符串  相同的目的地 
    ORA-00252: 日志  在线程  上为空,无法存档 
    ORA-00253: 字符限制在  以内,归档目的字符串  超出此限制 
    ORA-00254: 存档控制字符串 '' 时出错 
    ORA-00255: 存档日志  (线程 , 序列 # ) 时出错 
    ORA-00256: 无法翻译归档目的字符串  
    ORA-00257: 存档器错误。在释放之前仅限于内部连接 
    ORA-00258: NOARCHIVELOG 模式下的人工存档必须标识日志 
    ORA-00259: 日志  (打开线程 ) 为当前日志,无法存档 
    ORA-00260: 无法找到联机日志序列  (线程 ) 
    ORA-00261: 正在存档或修改日志  (线程 ) 
    ORA-00262: 当前日志  (关闭线程 ) 无法切换 
    ORA-00263: 线程  没有需要存档的记录 
    ORA-00264: 不要求恢复 
    ORA-00265: 要求例程恢复,无法设置 ARCHIVELOG 模式 
    ORA-00266: 需要存档日志文件名 
    ORA-00267: 无需存档日志文件名 
    ORA-00268: 指定的日志文件不存在 '' 
    ORA-00269: 指定的日志文件为线程  的一部分 (非 ) 
    ORA-00270: 创建存档日志  时出错 
    ORA-00271: 没有需要存档的日志 
    ORA-00272: 写存档日志  时出错 
    ORA-00273: 未记录的直接加载数据的介质恢复 
    ORA-00274: 非法恢复选项  
    ORA-00275: 已经开始介质恢复 
    ORA-00276: CHANGE 关键字已指定但未给出更改编号 
    ORA-00277: UNTIL 恢复标志  的非法选项 
    ORA-00278: 此恢复不再需要日志文件 '' 
    ORA-00279: 更改  (在  生成) 对于线程  是必需的 
    ORA-00280: 更改  对于线程  是按序列 #  进行的 
    ORA-00281: 不能使用调度进程执行介质恢复 
    ORA-00282: UPI  调用不被支持,请使用 ALTER DATABASE RECOVER 
    ORA-00283: 恢复会话因错误而取消 
    ORA-00284: 恢复会话仍在进行 
    ORA-00285: TIME 未作为字符串常数给出 
    ORA-00286: 无可用成员,或成员无有效数据 
    ORA-00287: 未找到指定的更改编号  (在线程  中) 
    ORA-00288: 要继续恢复,请键入 ALTER DATABASE RECOVER CONTINUE 
    ORA-00289: 建议:  
    ORA-00290: 操作系统出现存档错误。请参阅下面的错误 
    ORA-00291: PARALLEL 选项要求数字值 
    ORA-00292: 未安装并行恢复功能 
    ORA-00293: 控制文件与重做日志不同步 
    ORA-00294: 无效的存档日志格式标识 '' 
    ORA-00295: 数据文件号  无效,必须介于 1 与  之间 
    ORA-00296: 已超出 RECOVER DATAFILE LIST 的最大文件数 () 
    ORA-00297: 必须在 RECOVER DATAFILE START 之前指定 RECOVER DATAFILE LIST 
    ORA-00298: 丢失或无效的 TIMEOUT 间隔 
    ORA-00299: 必须在数据文件  上使用文件级介质恢复 
    ORA-00300: 指定的重做日志块大小  非法 - 超出限制  
    ORA-00301: 添加日志文件 '' 时出错 - 无法创建文件 
    ORA-00302: 日志超出限制  
    ORA-00303: 无法处理多次中断的重做 
    ORA-00304: 请求的 INSTANCE_NUMBER 在使用中 
    ORA-00305: 日志  (线程 ) 不一致;属于另一个数据库 
    ORA-00306: 此数据库中的例程限制  
    ORA-00307: 请求的 INSTANCE_NUMBER 超出限制,最大为  
    ORA-00308: 无法打开存档日志 '' 
    ORA-00309: 日志属于错误的数据库 
    ORA-00310: 存档日志包含序列 ;要求序列  
    ORA-00311: 无法从存档日志读取标题 
    ORA-00312: 联机日志  线程 : '' 
    ORA-00313: 无法打开日志组  (线程 ) 的成员 
    ORA-00314: 日志  (线程 ),预计序号  与  不匹配 
    ORA-00315: 日志  (线程 ),标题中的线程 #  错误 
    ORA-00316: 日志  (线程 ),标题中的类型  不是日志文件 
    ORA-00317: 标题中的文件类型  不是日志文件 
    ORA-00318: 日志  (线程 ),预计文件大小  与  不匹配 
    ORA-00319: 日志  (线程 ) 具有错误的日志重置状态 
    ORA-00320: 无法从日志  (线程 ) 读取文件标题 
    ORA-00321: 日志  (线程 ),无法更新日志文件标题 
    ORA-00322: 日志  (线程 ) 不是当前副本 
    ORA-00323: 线程  的当前日志不可用而所有其它日志均需要存档 
    ORA-00324: 日志文件 '' 的翻译名 '' 太长, 字符超出  限制 
    ORA-00325: 已归档线程  的日志,标题中的线程 #  错误 
    ORA-00326: 日志在更改  开始,需要更早的更改  
    ORA-00327: 日志  (线程 ),实际大小  小于需要的  
    ORA-00328: 归档日志在更改  结束,需要稍后的更改  
    ORA-00329: 归档日志在更改  开始,需要更改  
    ORA-00330: 归档日志在更改  结束,需要更改  
    ORA-00331: 日志版本  与 ORACLE 版本  不兼容 
    ORA-00332: 归档日志过小 - 可能未完全归档 
    ORA-00333: 重做日志读取块  计数  出错 
    ORA-00334: 归档日志: '' 
    ORA-00335: 联机日志 : 没有此编号的日志,日志不存在 
    ORA-00336: 大小为  的日志文件块数小于最小  块数 
    ORA-00337: 日志文件 '' 不存在且未指定大小 
    ORA-00338: 日志  (线程 ) 比控制文件更新 
    ORA-00339: 归档日志未包含任何重做 
    ORA-00340: 处理联机日志  (线程 ) 时出现 I/O 错误 
    ORA-00341: 日志  (线程 ),标题中的日志 #  错误 
    ORA-00342: 归档日志在上一个 RESETLOGS 之前创建程序包 
    ORA-00343: 错误过多,已关闭日志成员 
    ORA-00344: 无法重新创建联机日志 '' 
    ORA-00345: 重做日志写入块  计数  出错 
    ORA-00346: 日志成员标记为 STALE 
    ORA-00347: 日志  (线程 ),预计块大小  与  不匹配 
    ORA-00348: 单一进程重做失败;必须中止例程 
    ORA-00349: 无法获得 '' 的块大小 
    ORA-00350: 日志  (线程 ) 中需要归档 
    ORA-00351: recover-to 时间无效 
    ORA-00352: 线程  的所有日志均需要归档 - 无法启用 
    ORA-00353: 日志损坏接近块  更改  时间  
    ORA-00354: 损坏重做日志块标题 
    ORA-00355: 更改编号无次序 
    ORA-00356: 更改说明中的长度不一致 
    ORA-00357: 日志文件指定了过多成员,最大为  
    ORA-00358: 指定了过多文件成员,最大为  
    ORA-00359: 日志文件组  不存在 
    ORA-00360: 非日志文件成员:  
    ORA-00361: 无法删除最后一个日志成员  (组 ) 
    ORA-00362: 组成组  中的有效日志文件要求输入成员 
    ORA-00363: 日志不是归档版本 
    ORA-00364: 无法将标题写入新日志成员 
    ORA-00365: 指定日志不是正确的下一个日志 
    ORA-00366: 日志  (线程 ),文件标题中的校验和错误 
    ORA-00367: 日志文件标题中的校验和错误 
    ORA-00368: 重做日志块中的校验和错误 
    ORA-00369: 线程  的当前日志不可用且其它日志已被清除 
    ORA-00370: Rcbchange 操作过程中可能出现死锁 
    ORA-00371: 共享池内存不足 
    ORA-00372: 此时无法修改文件  
    ORA-00373: 联机日志版本  与 ORACLE 版本  不兼容 
    ORA-00374: 参数 db_block_size =  无效; 它必须是  的倍数, 范围为 [..] 
    ORA-00375: 无法获得默认 db_block_size 
    ORA-00376: 此时无法读取文件  
    ORA-00377: 文件  的频繁备份导致写操作延迟 
    ORA-00378: 无法按指定创建缓冲池 
    ORA-00379: 缓冲池  中无法提供 K 块大小的空闲缓冲区 
    ORA-00380: 无法指定 db_k_cache_size, 因为 K 是标准块大小 
    ORA-00381: 无法将新参数和旧参数同时用于缓冲区高速缓存的大小说明 
    ORA-00382:  不是有效的块大小, 有效范围为 [..] 
    ORA-00383: DEFAULT 高速缓存的块大小  不能减少至零 
    ORA-00384: 没有足够的内存来增加高速缓存的大小 
    ORA-00385: cannot enable Very Large Memory with new buffer cache parameters 
    ORA-00390: 日志  (线程 ) 正被清除,无法成为当前日志 
    ORA-00391: 所有线程必须同时转换为新的日志格式 
    ORA-00392: 日志  (线程 ) 正被清除,不允许操作 
    ORA-00393: 脱机数据文件的恢复需要日志  (线程 ) 
    ORA-00394: 在尝试存档时重新使用联机日志 
    ORA-00395: '克隆' 数据库的联机日志必须重命名 
    ORA-00396: 错误  需要退回到单次遍历恢复 
    ORA-00397: 对于文件  (块 ), 检测到写入丢失情况 
    ORA-00398: 由于重新配置而中止了线程恢复 
    ORA-00399: 重做日志中的更改说明已损坏 
    ORA-00400: 无效的版本值  (对于参数 ) 
    ORA-00401: 此版本不支持参数  的值 
    ORA-00402: 版本  的数据库更改无法用于版本  
    ORA-00403:  () 不同于其它例程 () 
    ORA-00404: 未找到转换文件: '' 
    ORA-00405: 兼容类型"" 
    ORA-00406: COMPATIBLE 参数需要为  或更大 
    ORA-00407: 不允许从版本 . 到 . 滚动升级 
    ORA-00408: 参数  设置为 TRUE 
    ORA-00409: COMPATIBLE 必须是  或更高值才能使用 AUTO SEGMENT SPACE MANAGEMENT 
    ORA-00436: 没有 ORACLE 软件使用权,请与 Oracle 公司联系获得帮助 
    ORA-00437: 没有 ORACLE 软件功能使用权,请与 Oracle 公司联系获得帮助 
    ORA-00438: 未安装  选项 
    ORA-00439: 未启用特性:  
    ORA-00443: 背景进程 "" 未启动 
    ORA-00444: 背景进程 "" 启动时失败 
    ORA-00445: 背景进程 "" 在  秒之后仍没有启动 
    ORA-00446: 背景进程意外启动 
    ORA-00447: 背景进程出现致命错误 
    ORA-00448: 背景进程正常结束 
    ORA-00449: 背景进程 '' 因错误  异常终止 
    ORA-00470: LGWR 进程因错误而终止 
    ORA-00471: DBWR 进程因错误而终止 
    ORA-00472: PMON 进程因错误而终止 
    ORA-00473: ARCH 进程因错误而终止 
    ORA-00474: SMON 进程因错误而终止 
    ORA-00475: TRWR 进程因错误而终止 
    ORA-00476: RECO 进程因错误而终止 
    ORA-00477: SNP* 进程因错误而终止 
    ORA-00478: SMON 进程由于  错误终止 
    ORA-00480: LCK* 进程因错误而终止 
    ORA-00481: LMON 进程因错误而终止 
    ORA-00482: LMD* 进程因错误而终止 
    ORA-00483: 关闭进程过程中异常终止 
    ORA-00484: LMS* 进程因错误而终止 
    ORA-00485: DIAG 进程由于  错误终止 
    ORA-00486: 功能不可用 
    ORA-00568: 超出中断处理程序的最大数 
    ORA-00574: osndnt: $CANCEL 失败 (中断) 
    ORA-00575: osndnt: $QIO 失败 (发送 out-of-band 中断) 
    ORA-00576: 带内中断协议错误 
    ORA-00577: 带外中断协议错误 
    ORA-00578: 重置协议错误 
    ORA-00579: osndnt: 服务器收到连接请求格式不正确 
    ORA-00580: 协议版本不匹配 
    ORA-00581: osndnt: 无法分配上下文区域 
    ORA-00582: osndnt: 无法撤消分配上下文区域 
    ORA-00583: osndnt: $TRNLOG 失败 
    ORA-00584: 无法关闭连接 
    ORA-00585: 主机名称格式错误 
    ORA-00586: osndnt: LIB$ASN_WTH_MBX 失败 
    ORA-00587: 无法连接到远程主机 
    ORA-00588: 来自主机的信息过短 
    ORA-00589: 来自主机的信息数据长度错误 
    ORA-00590: 来自主机的信息类型错误 
    ORA-00591: 写入的字节数错误 
    ORA-00592: osndnt: $QIO 失败 (邮箱队列) 
    ORA-00593: osndnt: $DASSGN 失败 (网络设备) 
    ORA-00594: osndnt: $DASSGN 失败 (邮箱) 
    ORA-00595: osndnt: $QIO 失败 (接收) 
    ORA-00596: osndnt: $QIO 失败 (发送) 
    ORA-00597: osndnt: $QIO 失败 (邮箱队列) 
    ORA-00598: osndnt: $QIO IO 失败 (邮箱读取) 
    ORA-00600: 内部错误代码,参数: [], [], [], [], [], [], [], [] 
    ORA-00601: 清除锁定冲突 
    ORA-00602: 内部编程异常错误 
    ORA-00603: ORACLE 服务器会话因致命错误而终止 
    ORA-00604: 递归 SQL 层  出现错误 
    ORA-00606: 内部错误代码 
    ORA-00607: 当更改数据块时出现内部错误 
    ORA-00701: 无法改变热启动数据库所需的对象 
    ORA-00702: 引导程序版本 '' 与版本 '' 不一致 
    ORA-00703: 超出行高速缓存例程锁的最大数 
    ORA-00704: 引导程序进程失败 
    ORA-00705: 启动过程中的状态不一致;请在关闭例程后重新启动 
    ORA-00706: 更改文件 '' 的格式时出错 
    ORA-00816: 错误信息无法转换 
    ORA-00900: 无效 SQL 语句 
    ORA-00901: 无效 CREATE 命令 
    ORA-00902: 无效数据类型 
    ORA-00903: 表名无效 
    ORA-00904: : 无效的标识符 
    ORA-00905: 缺少关键字 
    ORA-00906: 缺少左括号 
    ORA-00907: 缺少右括号 
    ORA-00908: 缺少 NULL 关键字 
    ORA-00909: 参数个数无效 
    ORA-00910: 指定的长度对于数据类型而言过长 
    ORA-00911: 无效字符 
    ORA-00913: 值过多 
    ORA-00914: 缺少 ADD 关键字 
    ORA-00915: 当前不允许网络访问字典表 
    ORA-00917: 缺少逗号 
    ORA-00918: 未明确定义列 
    ORA-00919: 无效函数 
    ORA-00920: 无效的关系运算符 
    ORA-00921: 未预期的 SQL 命令结尾 
    ORA-00922: 缺少或无效选项 
    ORA-00923: 未找到预期 FROM 关键字 
    ORA-00924: 缺少 BY 关键字 
    ORA-00925: 缺失 INTO 关键字 
    ORA-00926: 缺少 VALUES 关键字 
    ORA-00927: 缺少等号 
    ORA-00928: 缺少 SELECT 关键字 
    ORA-00929: 缺少句号 
    ORA-00930: 缺少星号 
    ORA-00931: 缺少标识 
    ORA-00932: 不一致的数据类型: 要求  得到的却是  
    ORA-00933: SQL 命令未正确结束 
    ORA-00934: 此处不允许使用分组函数 
    ORA-00935: 分组函数的嵌套太深 
    ORA-00936: 缺少表达式 
    ORA-00937: 非单组分组函数 
    ORA-00938: 函数没有足够的参数 
    ORA-00939: 函数的参数过多 
    ORA-00940: 无效的 ALTER 命令 
    ORA-00941: 群集名缺少 
    ORA-00942: 表或视图不存在 
    ORA-00943: 群集不存在 
    ORA-00944: 没有足够的聚簇列数 
    ORA-00945: 指定的聚簇列不存在 
    ORA-00946: 缺少 TO 关键字 
    ORA-00947: 没有足够的值 
    ORA-00948: 不再支持 ALTER CLUSTER 语句 
    ORA-00949: 非法引用远程数据库 
    ORA-00950: 无效 DROP 选项 
    ORA-00951: 群集非空 
    ORA-00952: 缺少 GROUP 关键字 
    ORA-00953: 缺少或无效索引名 
    ORA-00954: 缺少 IDENTIFIED 关键字 
    ORA-00955: 名称已由现有对象使用 
    ORA-00956: 缺少或无效审计选项 
    ORA-00957: 列名重复 
    ORA-00958: 缺少 CHECK 关键字 
    ORA-00959: 表空间''不存在 
    ORA-00960: 选择列表中的命名含糊 
    ORA-00961: 错误的日期/间隔值 
    ORA-00962: group-by / order-by 表达式过多 
    ORA-00963: 不支持的间隔类型 
    ORA-00964: 表名不在 FROM 列表中 
    ORA-00965: 列别名中不允许'*' 
    ORA-00966: 缺少 TABLE 关键字 
    ORA-00967: 缺少 WHERE 关键字 
    ORA-00968: 缺少 INDEX 关键字 
    ORA-00969: 缺少 ON 关键字 
    ORA-00970: 缺少 WITH 关键字 
    ORA-00971: 缺少 SET 关键字 
    ORA-00972: 标识过长 
    ORA-00973: 无效的行数估计 
    ORA-00974: 无效 PCTFREE 值 (百分比) 
    ORA-00975: 不允许日期 + 日期 
    ORA-00976: 此处不允许为 LEVEL, PRIOR 或 ROWNUM 
    ORA-00977: 重复的审计选项 
    ORA-00978: 嵌套分组函数没有 GROUT BY 
    ORA-00979: 不是 GROUP BY 表达式 
    ORA-00980: 同义词转换不再有效 
    ORA-00981: 不能将表和系统审计选项混在一起 
    ORA-00982: 缺少加号 
    ORA-00984: 列在此处不允许 
    ORA-00985: 无效的程序名 
    ORA-00986: 缺少或无效组名 
    ORA-00987: 缺少或无效用户名 
    ORA-00988: 缺少或无效口令 
    ORA-00989: 给出的用户名口令过多 
    ORA-00990: 缺少或无效权限 
    ORA-00991: 过程仅有 MAC 权限 
    ORA-00992: REVOKE 命令格式无效 
    ORA-00993: 缺少 GRANT 关键字 
    ORA-00994: 缺少 OPTION 关键字 
    ORA-00995: 缺少或无效同义词标识 
    ORA-00996: 连接运算符是 || 而不是 | 
    ORA-00997: 非法使用 LONG 数据类型 
    ORA-00998: 必须使用列别名命名此表达式 
    ORA-00999: 无效的视图名 
    ORA-01000: 超出打开游标的最大数 
    ORA-01001: 无效的游标 
    ORA-01002: 读取违反顺序 
    ORA-01003: 语句未进行语法分析 
    ORA-01004: 不支持默认用户名特性;登录被拒绝 
    ORA-01005: 未给出口令;登录被拒绝 
    ORA-01006: 赋值变量不存在 
    ORA-01007: 选择列表中没有变量 
    ORA-01008: 并非所有变量都已关联 
    ORA-01009: 缺少法定参数 
    ORA-01010: 无效的 OCI 操作 
    ORA-01011: 在与第 6 版服务器会话时不能使用第 7 版兼容模式 
    ORA-01012: 没有登录 
    ORA-01013: 用户请求取消当前的操作 
    ORA-01014: ORACLE 正在关闭过程中 
    ORA-01015: 循环登录请求 
    ORA-01016: 此函数仅可以在读取后调用 
    ORA-01017: 无效的用户名/口令;拒绝登录 
    ORA-01018: 列不具有 LONG 数据类型 
    ORA-01019: 无法在用户方分配内存 
    ORA-01020: 未知的上下文状态 
    ORA-01021: 指定的上下文大小无效 
    ORA-01022: 此配置中不支持数据库操作 
    ORA-01023: 未找到游标上下文 (无效的游标编号) 
    ORA-01024: OCI 调用中的数据类型无效 
    ORA-01025: UPI 参数超出范围 
    ORA-01026: 赋值列表中存在多个大小 > 4000 的缓冲区 
    ORA-01027: 在数据定义操作中不允许对变量赋值 
    ORA-01028: 内部双工错误 
    ORA-01029: 内部双工错误 
    ORA-01030: SELECT ...INTO 变量不存在 
    ORA-01031: 权限不足 
    ORA-01032: 没有这样的用户标识 
    ORA-01033: ORACLE 正在初始化或关闭过程中 
    ORA-01034: ORACLE 不可用 
    ORA-01035: ORACLE 只允许具有 RESTRICTED SESSION 权限的用户使用 
    ORA-01036: 非法的变量名/编号 
    ORA-01037: 超出最大游标内存 
    ORA-01038: 无法写入数据库文件版本  (使用 ORACLE 版本 ) 
    ORA-01039: 视图基本对象的权限不足 
    ORA-01040: 口令中的字符无效;登录被拒绝 
    ORA-01041: 内部错误,hostdef 扩展名不存在 
    ORA-01042: 不允许使用打开游标分离会话 
    ORA-01043: 用户方内存损坏 [], [], [], [] 
    ORA-01044: 缓冲区大小  (与变量关联) 超出了最大限制  
    ORA-01045: 用户  没有 CREATE SESSION 权限;登录被拒绝 
    ORA-01046: 无法获得扩展上下文区域的空间 
    ORA-01047: 以上错误出现在 schema=, package=, procedure= 中 
    ORA-01048: 给定的上下文中无法找到指定的过程 
    ORA-01049: 流动 RPC 中不支持按名称赋值 
    ORA-01050: 无法获得打开上下文区域的空间 
    ORA-01051: 延迟 rpc 缓冲区格式无效 
    ORA-01052: 未指定所需的目的 LOG_ARCHIVE_DUPLEX_DEST 
    ORA-01053: 无法读取用户存储地址 
    ORA-01054: 无法写入用户存储地址 
    ORA-01057: 用户出口中引用的 block.field 无效或有歧义 
    ORA-01058: 内部 New Upi 接口错误 
    ORA-01059: 在赋值或执行之前进行语法分析 
    ORA-01060: 不允许数组赋值或执行 
    ORA-01061: 无法使用第 7 版客户应用程序启动第 8 版服务器 
    ORA-01062: 无法分配定义缓冲区所需的内存 
    ORA-01070: 服务器使用 Oracle 的旧版本 
    ORA-01071: 无法不启动 ORACLE 而执行操作 
    ORA-01072: 无法停止 ORACLE;因为 ORACLE 不在运行 
    ORA-01073: 致命的连接错误: 不能识别的调用类型 
    ORA-01074: 无法关闭 ORACLE;请首先在注册会话中注销 
    ORA-01075: 您现在已登录 
    ORA-01076: 尚不支持每个进程的多次登录 
    ORA-01077: 背景进程初始化失败 
    ORA-01078: 处理系统参数失败 
    ORA-01079: ORALCE 数据库未正确创建,操作中止 
    ORA-01080: 关闭 ORACLE 时出错 
    ORA-01081: 无法启动已在运行的 ORACLE --- 请首先关闭 
    ORA-01082: 'row_locking = always' 要求事务处理处理选项 
    ORA-01083: 参数 "" 的值与其它例程序的相应参数值不一致。 
    ORA-01084: OCI 调用中的参数无效 
    ORA-01085: 延迟 rpc 到 ".." 之前的错误 
    ORA-01086: 从未创建保留点 '' 
    ORA-01087: 不能启动 ORALCE --- 现在已登录 
    ORA-01088: 不能在存在活动进程时关闭 ORACLE 
    ORA-01089: 正在进行紧急关闭 - 不允许进行任何操作 
    ORA-01090: 正在进行关闭 --- 不允许连接 
    ORA-01091: 强行启动出错 
    ORA-01092: ORACLE 例程终止。强行断开连接 
    ORA-01093: ALTER DATABASE CLOSE 仅允许在没有连接会话时使用 
    ORA-01094: ALTER DATABASE CLOSE 正在进行。不允许连接 
    ORA-01095: DML 语句处理了零个行 
    ORA-01096: 程序版本 () 与例程 () 不兼容 
    ORA-01097: 无法在事务处理过程中关闭 - 首先提交或返回 
    ORA-01098: 在 Long Insert 过程中出现程序接口错误 
    ORA-01099: 如果在单进程模式下启动,则无法在 SHARED 模式下安装数据库 
    ORA-01100: 数据库已安装 
    ORA-01101: 要创建的数据库当前正由其它例程安装 
    ORA-01102: 无法在 EXCLUSIVE 模式下安装数据库 
    ORA-01103: 控制文件中的数据库名 '' 不是 '' 
    ORA-01104: 控制文件数 () 不等于  
    ORA-01105: 安装与其它例程的安装不兼容 
    ORA-01106: 必须在卸下之前关闭数据库 
    ORA-01107: 必须安装数据库才可以进行介质恢复 
    ORA-01108: 文件  正处于备份或介质恢复过程中 
    ORA-01109: 数据库未打开 
    ORA-01110: 数据文件 : '' 
    ORA-01111: 数据文件  名称未知 - 请重命名以更正文件 
    ORA-01112: 未启动介质恢复 
    ORA-01113: 文件  需要介质恢复 
    ORA-01114: 将块写入文件  时出现 IO 错误 (块 # ) 
    ORA-01115: 从文件  读取块时出现 IO 错误 (块 # ) 
    ORA-01116: 打开数据库文件时出错 
    ORA-01117: 对文件 '' 添加非法块大小: ;限制为  
    ORA-01118: 无法添加任何其它数据库文件: 超出限制  
    ORA-01119: 创建数据库文件 '' 时出错 
    ORA-01120: 无法删除联机数据库文件  
    ORA-01121: 无法重命名数据库文件  - 文件在使用中或在恢复中 
    ORA-01122: 数据库文件  验证失败 
    ORA-01123: 无法启动联机备份;未启用介质恢复 
    ORA-01124: 无法恢复数据文件  - 文件在使用中或在恢复中 
    ORA-01125: 无法禁用介质恢复 - 文件  设置了联机备份 
    ORA-01126: 对于此操作,数据库必须以 EXCLUSIVE 模式安装且未打开 
    ORA-01127: 数据库名 '' 超出  个字符的限制 
    ORA-01128: 无法启动联机备份 - 文件  处于脱机状态 
    ORA-01129: 用户默认或临时表空间不存在 
    ORA-01130: 数据库文件版本  与 ORACLE 版本  不兼容 
    ORA-01131: DB_FILES 系统参数值  超出限制  
    ORA-01132: 数据库文件名 '' 的长度超出  个字符的限制 
    ORA-01133: 日志文件名 '' 的长度超出  个字符的限制 
    ORA-01134: 数据库已由其它例程独立安装 
    ORA-01135: DML/query 访问的文件  处于脱机状态 
    ORA-01136: 文件  ( 块) 的指定大小小于  块的原大小 
    ORA-01137: 数据文件  仍处于脱机过程中 
    ORA-01138: 数据库必须在此例程中打开或根本没有打开 
    ORA-01139: RESETLOGS 选项仅在不完全数据库恢复后有效 
    ORA-01140: 无法结束联机备份 - 所有文件均处于脱机状态 
    ORA-01141: 重命名数据文件  时出错 - 未找到新文件 '' 
    ORA-01142: 无法结束联机备份 - 没有文件在备份中 
    ORA-01143: 不能禁用介质恢复 - 文件  需要介质恢


    展开全文
  • 浅谈进程地址空间与虚拟存储空间

    万次阅读 多人点赞 2015-04-17 19:35:47
    有些非恶意的,但是有 bug 的程序也可能不小心修改了其它程序的内存数据,就会导致其它程序的运行出现异常。这种情况对用户来说是无法容忍的,因为用户希望使用计算机的时候,其中一个任务失败了,至少不能影响其它...

    早期的内存分配机制

    在早期的计算机中,要运行一个程序,会把这些程序全都装入内存,程序都是直接运行在内存上的,也就是说程序中访问的内存地址都是实际的物理内存地址。当计算机同时运行多个程序时,必须保证这些程序用到的内存总量要小于计算机实际物理内存的大小。

     

    那当程序同时运行多个程序时,操作系统是如何为这些程序分配内存 的呢?下面通过实例来说明当时的内存分配方法:

     

    某台计算机总的内存大小是 128M ,现在同时运行两个程序 A 和 B , A 需占用内存 10M , B 需占用内存 110 。计算机在给程序分配内存时会采取这样的方法:先将内存中的前 10M 分配给程序 A ,接着再从内存中剩余的 118M 中划分出 110M 分配给程序 B 。这种分配方法可以保证程序 A 和程序 B 都能运行,但是这种简单的内存分配策略问题很多。

     

     

     

    早期的内存分配方法

     

    问题 1 :进程地址空间不隔离。由于程序都是直接访问物理内存,所以恶意程序可以随意修改别的进程的内存数据,以达到破坏的目的。有些非恶意的,但是有 bug 的程序也可能不小心修改了其它程序的内存数据,就会导致其它程序的运行出现异常。这种情况对用户来说是无法容忍的,因为用户希望使用计算机的时候,其中一个任务失败了,至少不能影响其它的任务。

     

    问题 2 :内存使用效率低。在 A 和 B 都运行的情况下,如果用户又运行了程序 C,而程序 C 需要 20M 大小的内存才能运行,而此时系统只剩下 8M 的空间可供使用,所以此时系统必须在已运行的程序中选择一个将该程序的数据暂时拷贝到硬盘上,释放出部分空间来供程序 C 使用,然后再将程序 C 的数据全部装入内存中运行。可以想象得到,在这个过程中,有大量的数据在装入装出,导致效率十分低下。

     

    问题 3 :程序运行的地址不确定。当内存中的剩余空间可以满足程序 C 的要求后,操作系统会在剩余空间中随机分配一段连续的 20M 大小的空间给程序 C 使用,因为是随机分配的,所以程序运行的地址是不确定的。

     

    分段

    为 了解决上述问题,人们想到了一种变通的方法,就是增加一个中间层,利用一种间接的地址访问方法访问物理内存。按照这种方法,程序中访问的内存地址不再是实际的物理内存地址,而是一个虚拟地址,然后由操作系统将这个虚拟地址映射到适当的物理内存地址上。这样,只要操作系统处理好虚拟地址到物理内存地址的映射,就可以保证不同的程序最终访问的内存地址位于不同的区域,彼此没有重叠,就可以达到内存地址空间隔离的效果。

     

    当创建一个进程时,操作系统会为该进程分配一个 4GB 大小的虚拟进程地址空间。之所以是 4GB ,是因为在 32 位的操作系统中,一个指针长度是 4 字节,而 4 字节指针的寻址能力是从 0x00000000~0xFFFFFFFF,最大值 0xFFFFFFFF 表示的即为 4GB 大小的容量。与虚拟地址空间相对的,还有一个物理地址空间,这个地址空间对应的是真实的物理内存。如果你的计算机上安装了 512M 大小的内存,那么这个物理地址空间表示的范围是 0x00000000~0x1FFFFFFF 。当操作系统做虚拟地址到物理地址映射时,只能映射到这一范围,操作系统也只会映射到这一范围。当进程创建时,每个进程都会有一个自己的 4GB 虚拟地址空间。要注意的是这个 4GB 的地址空间是“虚拟”的,并不是真实存在的,而且每个进程只能访问自己虚拟地址空间中的数据,无法访问别的进程中的数据,通过这种方法实现了进程间的地址隔离。那是不是这 4GB 的虚拟地址空间应用程序可以随意使用呢?很遗憾,在 Windows 系统下,这个虚拟地址空间被分成了 4 部分: NULL 指针区、用户区、 64KB 禁入区、内核区。

     

    1)NULL指针区 (0x00000000~0x0000FFFF): 如果进程中的一个线程试图操作这个分区中的数据,CPU就会引发非法访问。他的作用是,调用 malloc 等内存分配函数时,如果无法找到足够的内存空间,它将返回 NULL。而不进行安全性检查。它只是假设地址分配成功,并开始访问内存地址 0x00000000(NULL)。由于禁止访问内存的这个分区,因此会发生非法访问现象,并终止这个进程的运行。


    2)用户模式分区 ( 0x00010000~0xBFFEFFFF):这个分区中存放进程的私有地址空间。一个进程无法以任何方式访问另外一个进程驻留在这个分区中的数据 (相同 exe,通过 copy-on-write 来完成地址隔离)。(在windows中,所有 .exe 和动态链接库都载入到这一区域。系统同时会把该进程可以访问的所有内存映射文件映射到这一分区)。


    2)隔离区 (0xBFFF0000~0xBFFFFFFF):这个分区禁止进入。任何试图访问这个内存分区的操作都是违规的。微软保留这块分区的目的是为了简化操作系统的现实。


    3)内核区 (0xC0000000~0xFFFFFFFF):这个分区存放操作系统驻留的代码。线程调度、内存管理、文件系统支持、网络支持和所有设备驱动程序代码都在这个分区加载。这个分区被所有进程共享。

     

    应用程序能使用的只是用户区而已,大约 2GB 左右 ( 最大可以调整到 3GB) 。内核区为 2GB ,内核区保存的是系统线程调度、内存管理、设备驱动等数据,这部分数据供所有的进程共享,但应用程序是不能直接访问的。

     

    人们之所以要创建一个虚拟地址空间,目的是为了解决进程地址空间隔离的问题。但程序要想执行,必须运行在真实的内存上,所以,必须在虚拟地址与物理地址间建立一种映射关系。这样,通过映射机制,当程序访问虚拟地址空间上的某个地址值时,就相当于访问了物理地址空间中的另一个值。人们想到了一种分段(Sagmentation) 的方法,它的思想是在虚拟地址空间和物理地址空间之间做一一映射。比如说虚拟地址空间中某个 10M 大小的空间映射到物理地址空间中某个 10M 大小的空间。这种思想理解起来并不难,操作系统保证不同进程的地址空间被映射到物理地址空间中不同的区域上,这样每个进程最终访问到的。

     

    物理地址空间都是彼此分开的。通过这种方式,就实现了进程间的地址隔离。还是以实例说明,假设有两个进程 A 和 B ,进程 A 所需内存大小为 10M ,其虚拟地址空间分布在 0x00000000 到 0x00A00000 ,进程 B 所需内存为 100M ,其虚拟地址空间分布为 0x00000000 到 0x06400000 。那么按照分段的映射方法,进程 A 在物理内存上映射区域为 0x00100000 到 0x00B00000 ,,进程 B 在物理内存上映射区域为0x00C00000 到 0x07000000 。于是进程 A 和进程 B 分别被映射到了不同的内存区间,彼此互不重叠,实现了地址隔离。从应用程序的角度看来,进程 A 的地址空间就是分布在 0x00000000 到 0x00A00000 ,在做开发时,开发人员只需访问这段区间上的地址即可。应用程序并不关心进程 A 究竟被映射到物理内存的那块区域上了,所以程序的运行地址也就是相当于说是确定的了。 下图显示的是分段方式的内存映射方法: 

    分段方式的内存映射方法

     

    这种分段的映射方法虽然解决了上述中的问题一和问题三,但并没能解决问题二,即内存的使用效率问题。在分段的映射方法中,每次换入换出内存的都是整个程序, 这样会造成大量的磁盘访问操作,导致效率低下。所以这种映射方法还是稍显粗糙,粒度比较大。实际上,程序的运行有局部性特点,在某个时间段内,程序只是访问程序的一小部分数据,也就是说,程序的大部分数据在一个时间段内都不会被用到。基于这种情况,人们想到了粒度更小的内存分割和映射方法,这种方法就是分页 (Paging) 。  

     

    分页

    分页的基本方法是,将地址空间分成许多的页。每页的大小由 CPU 决定,然后由操作系统选择页的大小。目前 Inter 系列的 CPU 支持 4KB 或 4MB 的页大小,而 PC上目前都选择使用 4KB 。按这种选择, 4GB 虚拟地址空间共可以分成 1048576 页, 512M 的物理内存可以分为 131072 个页。显然虚拟空间的页数要比物理空间的页数多得多

     

    在分段的方法中,每次程序运行时总是把程序全部装入内存,而分页的方法则有所不同。分页的思想是程序运行时用到哪页就为哪页分配内存,没用到的页暂时保留在硬盘上。当用到这些页时再在物理地址空间中为这些页分配内存,然后建立虚拟地址空间中的页和刚分配的物理内存页间的映射。

     

    下面通过介绍一个可执行文件的装载过程来说明分页机制的实现方法。一个可执行文件 (PE 文件 ) 其实就是一些编译链接好的数据和指令的集合,它也会被分成很多页,在 PE 文件执行的过程中,它往内存中装载的单位就是页。当一个 PE 文件被执行时,操作系统会先为该程序创建一个 4GB 的进程虚拟地址空间。前面介绍过,虚拟地址空间只是一个中间层而已,它的功能是利用一种映射机制将虚拟地址空间映射到物理地址空间,所以,创建 4GB 虚拟地址空间其实并不是要真的创建空间,只是要创建那种映射机制所需要的数据结构而已,这种数据结构就是页目和页表。

     

    当创建完虚拟地址空间所需要的数据结构后,进程开始读取 PE 文件的第一页。在PE 文件的第一页包含了 PE 文件头和段表等信息,进程根据文件头和段表等信息,将 PE 文件中所有的段一一映射到虚拟地址空间中相应的页 (PE 文件中的段的长度都是页长的整数倍 ) 。这时 PE 文件的真正指令和数据还没有被装入内存中,操作系统只是据 PE 文件的头部等信息建立了 PE 文件和进程虚拟地址空间中页的映射关系而已。当 CPU 要访问程序中用到的某个虚拟地址时,当 CPU 发现该地址并没有相相关联的物理地址时, CPU 认为该虚拟地址所在的页面是个空页面, CPU 会认为这是个页错误 (Page Fault) , CPU 也就知道了操作系统还未给该 PE 页面分配内存,CPU 会将控制权交还给操作系统。操作系统于是为该 PE 页面在物理空间中分配一个页面,然后再将这个物理页面与虚拟空间中的虚拟页面映射起来,然后将控制权再还给进程,进程从刚才发生页错误的位置重新开始执行。由于此时已为 PE 文件的那个页面分配了内存,所以就不会发生页错误了。随着程序的执行,页错误会不断地产生,操作系统也会为进程分配相应的物理页面来满足进程执行的需求。

     

    分页方法的核心思想就是当可执行文件执行到第 x 页时,就为第 x 页分配一个内存页 y ,然后再将这个内存页添加到进程虚拟地址空间的映射表中 , 这个映射表就相当于一个 y=f(x) 函数。应用程序通过这个映射表就可以访问到 x 页关联的 y 页了。

     

    逻辑地址、线性地址、物理地址和虚拟地址的区别

    逻辑地址(Logical Address) 是指由程式产生的和段相关的偏移地址部分。例如,你在进行 C 语言指针编程中,能读取指针变量本身值( &操作 ),实际上这个值就是逻辑地址,他是相对于你当前进程数据段的地址,不和绝对物理地址相干。只有在 Intel 实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或分页机制,cpu不进行自动地址转换);逻辑也就是在Intel保护模式下程式执行代码段限长内的偏移地址(假定代码段、数据段如果完全相同)。应用程式员仅需和逻辑地址打交道,而分段和分页机制对你来说是完全透明的,仅由系统编程人员涉及。应用程式员虽然自己能直接操作内存,那也只能在操作系统给你分配的内存段操作。


    线性地址(Linear Address) 是逻辑地址到物理地址变换之间的中间层。程式代码会产生逻辑地址,或说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址能再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386 的线性地址空间容量为 4G(2的32次方即32根地址总线寻址)。


    物理地址(Physical Address) 是指出目前 CPU 外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了。


    虚拟内存(Virtual Memory)是指计算机呈现出要比实际拥有的内存大得多的内存量。因此他允许程式员编制并运行比实际系统拥有的内存大得多的程式。这使得许多大型项目也能够在具有有限内存资源的系统上实现。一个非常恰当的比喻是:你不必非常长的轨道就能让一列火车从上海开到北京。你只需要足够长的铁轨(比如说3公里)就能完成这个任务。采取的方法是把后面的铁轨即时铺到火车的前面,只要你的操作足够快并能满足需求,列车就能象在一条完整的轨道上运行。这也就是虚拟内存管理需要完成的任务。在 Linux0.11 内核中,给每个程式(进程)都划分了总容量为 64MB 的虚拟内存空间。因此程式的逻辑地址范围是 0x0000000 到 0x4000000。有时我们也把逻辑地址称为 虚拟地址。因为和虚拟内存空间的概念类似,逻辑地址也是和实际物理内存容量无关的。逻辑地址和物理地址的“差距”是 0xC0000000,是由于虚拟地址->线性地址->物理地址映射正好差这个值。这个值是由操作系统指定的。机理逻辑地址(或称为虚拟地址)到线性地址是由CPU的段机制自动转换的。如果没有开启分页管理,则线性地址就是物理地址。如果开启了分页管理,那么系统程式需要参和线性地址到物理地址的转换过程。具体是通过设置页目录表和页表项进行的。

     

    转自:游手好弦 信步涂鸦

    展开全文
  • Android存储空间及路径总结

    千次阅读 2019-05-27 17:20:40
    普通用户不能直接直观地查看目录文件等其他原因,Android 在外部存储空间中也提供有特殊目录供应用存放私有文件,文件路径为: /storage/emulated/0/Android/data/app包名目录 值得注意的是,与内部存储空间的应用...
  • java 存储空间 简单分析

    万次阅读 2016-08-20 01:37:59
    基础数据类型(Value type)直接在栈(stack)空间分配,方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收。 引用数据类型,需要用new来创建,既在栈空间分配一个地址空间(reference),又在堆空间分配...
  • Oracle 异常处理(函数、存储过程)

    千次阅读 2017-11-20 12:13:38
    Oracle 异常处理 一、概述 异常分成三大类:预定义异常、非预定义异常、自定义异常 处理方法分为:直接抛出异常、内部块处理异常、游标处理异常 预定义异常:由PL/SQL定义的异常。由于它们已在standard包中...
  • mysql存储引擎

    万次阅读 多人点赞 2019-07-31 19:28:44
    数据库存储引擎 数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还...
  • 由于公司终端产品的平台由三星的2440换到9260上(可能是由于9260更适合于工业场合上),... 按照惯例,先了解下9260的存储空间分配及其启动方式: 1. 9260的总线为32bit,因此其存储空间共有4G,一共分成16个bank,每个
  • Android开发——理解文件存储

    千次阅读 2016-10-16 13:20:32
    一、内部存储和外部存储的概念在Android中,我们可以把数据存储在SharedPreferences、内部存储、外部存储、SQLite数据库和网络上。其中内部存储指的是设备内存,一般存储私有数据;外部存储是共享的,可以用来存储...
  • Android数据存储

    千次阅读 2016-07-12 13:32:07
    数据存储在Android开发中是很重要的,因为做一个项目一定会用到数据存储,比如游戏或者应用的一些设置配置,游戏存档,应用使用习惯等。...ROM内存:存储内存,相当于电脑的硬盘外部存储空间SD卡:相当于电脑的移动硬
  • 在PLSQL程序开发过程中,很重要的部分就是对程序异常的监控和处理,包括如何触发异常,何时进行处理,如何进行处理,是否将程式中的所有异常集中在一起,通过公共异常处理的procedure或function,如果没有完善的程式...
  • Android文件存储

    千次阅读 2012-07-24 16:09:41
    所谓的内部存储与外部存储,是指是否是手机内置。手机内置的存储空间,称为内部存储,它是手机一旦出厂就无法改变,它也是手机的硬件指标之一,通常来讲手机内置存储空间越大意味着手机价格会越贵(很多地方把它称为...
  • .NET中异常处理的最佳实践(译)

    千次阅读 2015-02-25 13:19:56
    本文翻译自CodeProject上的一篇文章,原文地址。 目录 介绍做最坏的打算 提前检查不要信任外部数据可信任的设备:摄像头、鼠标以及键盘 “写操作...不要抛出“new Exception()”不要将重要的异常信息存储在Messag
  • Throwable:有两个重要的子类:Exception(异常)和Error(错误),二者都是Java异常处理的重要子类,各自都包含大量子类。 Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码...
  • Android数据存储-文件存储-内部存储

    千次阅读 2018-01-20 17:08:38
    所有的Android设备都有两个文件存储区域:内部存储和外部存储。内部存储都是指手机内部(这并不是说外部存储就是指的手机的外部SD卡之类的,外部存储物理上来说也有可能是在手机内部)。 内部存储中的文件只有您的...
  • 三、ARM存储空间  ARM的地址空间也可以看作是2 30 个32位的 字单元(4字节) 。这些字单元的地址可以被4整除,也就是说该地址的低两位为0b00。地址为A的字数包括地址A、A+1、A+2、A+3这4个字节单元的内容。...
  • Android存储路径详细说明

    万次阅读 2017-05-06 19:25:03
    外部缓存存储路径在有些手机上,系统也会在内部划出一个内部的SDCard路径和内部存储路径,所以当有SDCard的时候,就会有6个路径存在了内部存储空间中的应用私有目录对于设备中每一个安装的 App,系统都会在内部存储...
  • Android不同存储方式与所需权限

    千次阅读 2020-02-24 16:24:56
    首先,App在手机上保存文件或者缓存数据时,应该遵守以下几点: 1、不要随意占用用户的...Android系统分为内部存储和外部存储,内部存储是手机系统自带的存储,一般空间都比较小,外部存储一般是SD卡的存储,空间一...
  • HDFS内存存储

    万次阅读 2016-05-29 20:15:45
    前言 上一篇文章主要阐述了HDFS Cache缓存方面的知识,本文继续带领大家了解HDFS内存存储...就是之前HDFS异构存储中提到的内存存储策略,LAZY_PERSIST.换句话说,本文也是对HDFS内存存储策略的一个更细致的分析.考虑
  • 本篇博客主要讲授华大半导(STM32、C51等单片机均可适用)复位(以看门...这里将用到__not_init属性,其用于变量声明,可禁止系统启动时变量的初始化,有了__not_init属性,编译器只给指定变量分配空间,不会再初始化。
  • Android存储的实现

    千次阅读 2016-04-10 15:19:04
    2、保存和读取外部存储的内容; 3、保存和读取内部存储的内容; 4、对Android内嵌数据库SQLite的增删改查、更新版本等操作; 5、使用四大组件之一的ContentProvider,并结合ContentResolver或取内容
  • 深入理解Java虚拟机-Java内存区域与内存溢出异常

    万次阅读 多人点赞 2020-01-03 21:42:24
    存储空间,用于存储 方法参数 和 局部变量 。 在 Class 文件的方法表的 Code 属性的 max_locals 指定了该方法所需局部变量表的 最大容量 。 局部变量表 在编译期间分配内存空间,可以存放 编译期 的各种...
  • ARM 处理器 ~ 中断与异常

    千次阅读 2017-12-13 11:11:59
    中断与异常定义ARM 中的工作模式除 User 和 System 外,均为异常模式,这里的异常是广义的,包含以下三类情况外部中断(外部中断)由于 CPU 外部的原因而改变程序执行流程,属于异步事件,可以屏蔽软件中断(自陷) ...
  • 中断,异常,陷阱

    千次阅读 2011-01-17 14:39:00
    80386把外部中断称为“中断”,把内部中断称为“异常”。与8086/8088一样,80386通常在两条指令之间响应中断或异常。80386最多处理256种中断或异常。中断是由异步的外部事件引起的。外部事件及中断响应与正执行的...
  • &gt; 异常的分类: ① 异常的继承结构:基类为Throwable,Error和Exception继承Throwable,RuntimeException和...② Error和RuntimeException及其子类成为未检查异常(unchecked),其它异常成为已检查异...
  • mips下的异常、中断

    千次阅读 2016-03-08 22:40:45
    1. 外部事件 ——中断 2. 内存翻译异常 3. 其他不太常见的内核修改的程序条件 4. 程序或硬件探测到的错误 5. 数据完整性错误 6. 系统调用和陷入 精确异常 在运行流程中没有任何多余效应的异常。即当...
  • oracle调用外部C DLL

    千次阅读 2017-10-13 16:05:05
    一个外部程序是存储在一个动态链接库(DLL)中的第三代语言程序,使用PL / SQL注册,并通过你叫做特殊处理。该例程必须从C调用,但可以用任何语言编写。在运行时,PL / SQL动态加载库,然后调用该程序就像是PL / SQL...
  • 32位,在保护方式下,其能够访问的线性地址空间可达4GB,而且允许几乎不受存储空间限制的虚拟存储器程序。虚拟存储器地址空间能够可达64TB。它还提供了复杂的存储管理和硬件辅助的保护机构和增加了支持多任务操作...
  • Android文件存储API

    2014-06-23 13:17:39
    所谓的内部存储与外部存储,是指是否是手机内置。手机内置的存储空间,称为内部存储,它是手机一旦出厂就无法改变,它也是手机的硬件指标之一,通常来讲手机内置存储空间越大意味着手机价格会越贵(很多地方把它称为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 105,589
精华内容 42,235
关键字:

外部存储空间异常